Because of mathjax bug

The Duckiebook

🔗

The last version of this book and other documents are available at the URL
http://book.duckietown.org/

Google search the documentation (with some delay, for Google to index the pages)

Table of contents

🔗
Because of mathjax bug

The Duckietown project

🔗

What is Duckietown?

🔗

Goals and objectives

🔗

Duckietown is a robotics educations and outreach effort.

The most tangible goal of the project is to provide a low-cost educational platform for learning autonomy, consisting of the Duckiebots, an autonomous robot, and the Duckietowns, the infrastructure in which the Duckiebots navigate.

However, we focus on the learning experience as a whole, by providing a set of modules teaching plans and other guides, as well as a curated role-play experience.

We have two targets:

  1. For instructors, we want to create a “class-in-a-box” that allows to offer a modern and engaging learning experience. Currently, this is feasible at the advanced undergraduate and graduate level, though in the future we would like to present the platform as multi-grade experiences.

  2. For self-guided learners, we want to create a “self-learning experience”, that allows to go from zero knowledge of robotics to graduate-level understanding.

In addition, the Duckietown platform has been used as a research platform.

Learn about the Duckietown educational experience

🔗

This video is a Duckumentary about the first version of the class, during Spring 2016. The Duckumentary was shot by Chris Welch.

TODO: Add Duckumentary
The Duckumentary

See also this documentary by Red Hat:

The video is at https://vimeo.com/219731087.

The road to autonomy

If you’d like to know more about the educational experience, [1] present a more formal description of the course design for Duckietown: learning objectives, teaching methods, etc.

Learn about the platform

🔗

The best way to get a sense of how the platform looks is to watch these videos. They show off the capabilities of the platform.

If you would like to know more, the paper [2] describes the Duckiebot and its software. (With 29 authors, we made the record for a robotics conference!)

add the video here that we showed at ICRA.

Can you do it by night?

The video is at https://vimeo.com/152825632.

Cool Duckietown by night

Because of mathjax bug

Duckietown history and future

🔗

The beginnings of Duckietown

🔗

The original Duckietown class was at MIT in 2016.

Part of the first MIT class, during the final demo.

The video is at https://vimeo.com/152233002.

The need for autonomy

The video is at https://vimeo.com/152499589.

Advertisement

The video is at https://vimeo.com/149916365.

The elves of Duckietown

University-level classes in 2016

🔗

Later that year, the Duckietown platform was also used in these classes:

Duckietown at NCTU in 2016

University-level classes in 2017

🔗

In 2017, these four courses will be taught together, with the students interacting among institutions:

Furthermore, the Duckietown platform is used also in the following universities:

  • Rennselaer Polytechnic Institute (Jeff Trinkle)
  • National Chiao Tung University, Taiwan - Prof. Yon-Ping Chen’s Dynamic system simulation and implementation.
  • Chosun University, Korea - Prof. Woosuk Sung’s course;
  • Petra Christian University, Indonesia - Prof. Resmana Lim’s Mobile Robot Design Course
  • National Tainan Normal University, Taiwan - Prof. Jen-Jee Chen’s Vehicle to Everything (V2X) Course;
  • Yuan Zhu University, Taiwan - Prof. Kan-Lin Hsiung’s Control course;

Chile

🔗

to write

Duckietown High School

🔗

to write

Because of mathjax bug

Duckietown classes

🔗

Duckietown is an international effort. Many educational institutions have adopted the platform and used to teach robotics and related subjects. If you have used Duckietown in any of your course and cannot find a mention to it here, contact us.

add contact email

Here, we provide a chronologically ordered compendium of the Duckietown related learning experiences worldwide.

2016

🔗

Duckietown was created in 2016.

Massachusetts Institute of Technology

🔗

Location: United States of America, Cambridge, Massachusetts

Course title: 2.166 Vehicle Autonomy

Instructors: plenty

Educational Level: Graduate

Time period:

Link:

Highlights: Role-playing experience (Duckietown Engineering Co.), public demo

Summary:

Duckietown at MIT in 2016

National Chiao Tung University

🔗

Location:

Course title:

Instructors: Prof. Nick Wang

Educational Level:

Time period:

Link:

Summary:

Highlights:

Tsinghua University

🔗

Location:

Course title:

Instructors:

Educational Level:

Time period:

Link:

Summary:

Highlights:

Rennselaer Polytechnic Institute

🔗

Location:

Course title:

Instructors:

Educational Level:

Time period:

Link:

Summary:

Highlights:

2017

🔗

ETH Zürich

🔗

Censi/Tani

Université de Montréal

🔗

Location: Montreal

Course title: IFT 6080 Sujets en exploitation des ordinateurs

Instructors: Liam Paull

Educational Level: Graduate

Time period: Sept. - Dec. 2017

Link: Official Course Website

Summary: 12 students admitted spanning across Université de Montréal, École Polytechnic, McGill University and Concordia University

Highlights:

Toyota Technological Institute at Chicago / University of Chicago

🔗

Matt Walter

Because of mathjax bug

First steps

🔗

How to get started

🔗

If you are an instructor, please jump to Section 4.2.

If you are a self-guided learner, please jump to Section 4.3.

If you are a company, and interested in working with Duckietown, please jump to Section 4.4.

Duckietown for instructors

🔗

to write

Duckietown for self-guided learners

🔗

to write

Introduction for companies

🔗

to write

How to keep in touch

🔗

add link to Facebook

add link to Mailing list

add link to Slack?

How to contribute

🔗

If you want to contribute to the software…

If you want to contribute to the hardware…

If you want to contribute to the documentation…

If you want to contribute to the dissemination…

Because of mathjax bug

Frequently Asked Questions

🔗

General questions

🔗

What is Duckietown?

Duckietown is a low-cost educational and research platform.

Is Duckietown free to use?

Yes. All materials are released according to an open source license.

Is everything ready?

Not quite! Please sign up to our mailing list to get notified when things are a bit more ready.

How can I start?

See the section First Steps.

How can I help?

If you would like to help actively, please email duckietown@mit.edu.

FAQ by students / independent learners

🔗

I want to build my own Duckiebot. How do I get started?

to write

FAQ by instructors

🔗

How large a class can it be? I teach large classes.

to write

What is the budget for the robot?

to write

I want to teach a Duckietown class. How do I get started?

Please get in touch with us at duckietown@mit.edu. We will be happy to get you started and sign you up to the Duckietown instructors mailing list.

Why the duckies?

Compared to other educational robotics projects, the presence of the duckies is what makes this project stand out. Why the duckies?

We want to present robotics in an accessible and friendly way.

copy usual discussion from somewhere else.

add picture of kids with Duckiebots.

Because of mathjax bug

Duckumentation documentation

🔗
Because of mathjax bug

Accounts

🔗

Complete list of accounts

🔗

Currently, Duckietown has the following accounts:

  • Github: for source code, and issue tracking;
  • Slack: a forum for wide communication;
  • Twist: to be used for instructors coordination;
  • Google Drive: to be used for instructors coordination, maintaining TODOs, etc;
  • Dropbox Folders (part of Andrea’s personal accounts): to be abandoned;
  • Vimeo, for storing the videos;
  • The duckietown-teaching mailing list, for low-rate communication with instructors;
  • We also have a list of addresses, of people signed up on the website, that we didn’t use yet;
  • The Facebook page.

For other contributors

🔗

If you are an international contributor:

  • Sign up on Slack, to keep up with the project.
  • (optional) Get Github permissions if you do frequent updates to the repositories.
Because of mathjax bug

Contributing to the documentation

🔗

Where the documentation is

🔗

All the documentation is in the repository duckietown/duckuments.

The documentation is written as a series of small files in Markdown format.

It is then processed by a series of scripts to create this output:

🔗

The simplest way to contribute to the documentation is to click any of the “✎” icons next to the headers.

They link to the “edit” page in Github. There, one can make and commit the edits in only a few seconds.

Comments

🔗

In the multiple-page version, each page also includes a comment box powered by a service called Disqus. This provides a way for people to write comments with a very low barrier. (We would periodically remove the comments.)

Installing the documentation system

🔗

In the following, we are going to assume that the documentation system is installed in ~/duckuments. However, it can be installed anywhere.

We are also going to assume that you have setup a Github account with working public keys.

We are also going to assume that you have installed the duckietown/software in ~/duckietown.

Dependencies (Ubuntu 16.04)

🔗

On Ubuntu 16.04, these are the dependencies to install:

$ sudo apt install libxml2-dev libxslt1-dev
$ sudo apt install libffi6 libffi-dev
$ sudo apt install python-dev python-numpy python-matplotlib
$ sudo apt install virtualenv
$ sudo apt install bibtex2html pdftk

Download the duckuments repo

🔗

Download the duckietown/duckuments repository in that directory:

$ git clone git@github.com:duckietown/duckuments ~/duckuments

Setup the virtual environment

🔗

Next, we will create a virtual environment using inside the ~/duckuments directory.

Change into that directory:

$ cd ~/duckuments

Create the virtual environment using virtualenv:

$ virtualenv --system-site-packages deploy

Other distributions: In other distributions you might need to use venv instead of virtualenv.

Activate the virtual environment:

$ source ~/duckuments/deploy/bin/activate

Setup the mcdp external repository

🔗

Make sure you are in the directory:

$ cd ~/duckuments

Clone the mcdp external repository, with the branch duckuments.

$ git clone -b duckuments git@github.com:AndreaCensi/mcdp

Install it and its dependencies:

$ cd ~/duckuments/mcdp
$ python setup.py develop

If you get a permission error here, it means you have not properly activated the virtual environment.

Other distributions: If you are not on Ubuntu 16, depending on your system, you might need to install these other dependencies:

$ pip install numpy matplotlib

You also should run:

$ pip install -U SystemCmd==2.0.0

Compiling the documentation

🔗

Make sure you have deployed and activated the virtual environment. You can check this by checking which python is active:

$ which python
/home/user/duckuments/deploy/bin/python

Then:

$ cd ~/duckuments
$ make duckuments-dist

This creates the directory duckuments-dist, which contains another checked out copy of the repository, but with the branch gh-pages, which is the branch that is published by Github using the “Github Pages” mechanism.

At this point, please make sure that you have these two .git folders:

~/duckuments/.git
~/duckuments/duckuments-dist/.git

To compile the docs, run make clean compile:

$ make clean compile

To see the result, open the file

./duckuments-dist/master/duckiebook/index.html

Incremental compilation

🔗

If you want to do incremental compilation, you can omit the clean and just use:

$ make compile

This will be faster. However, sometimes it might get confused. At that point, do make clean.

Troubleshooting compilation

🔗

“Invalid XML”

“Markdown” doesn’t mean that you can put anything in a file. Except for the code blocks, it must be valid XML. For example, if you use “>” and “<” without quoting, it will likely cause a compile error.

“Tabs are evil”

Do not use tab characters. The error message in this case is quite helpful in telling you exactly where the tabs are.

The error message contains ValueError: Suspicious math fragment 'KEYMATHS000ENDKEY'

You probably have forgotten to indent a command line by at least 4 spaces. The dollar in the command line is now being confused for a math formula.

The workflow to edit documentation.

🔗

This is the workflow:

  1. Edit the Markdown in the master branch of the duckuments repository.
  2. Run make compile to make sure it compiles.
  3. Commit the Markdown and push on the master branch.

Done. A bot will redo the compilation and push the changes in the gh-pages branch.

Step 2 is there so you know that the bot will not encounter errors.

*Deploying the documentation

🔗

This part is now done by a bot, so you don’t need to do it manually.

To deploy the documentation, jump into the DUCKUMENTS/duckuments-dist directory.

Run the command git branch. If the out does not say that you are on the branch gh-pages, then one of the steps before was done incorrectly.

$ cd $DUCKUMENTS/duckuments-dist
$ git branch
...
* gh-pages
...

Now, after triple checking that you are in the gh-pages branch, you can use git status to see the files that were added or modified, and simply use git add, git commit and git push to push the files to Github.

*Compiling the PDF version

🔗

The dependencies below are harder to install. If you don’t manage to do it, then you only lose the ability to compile the PDF. You can do make compile to compile the HTML version, but you cannot do make compile-pdf.

Installing nodejs

🔗

Ensure the latest version (>6) of nodejs is installed.

Run:

$ nodejs --version
6.xx

If the version is 4 or less, remove nodejs:

$ sudo apt remove nodejs

Install nodejs using the instructions at this page.

Next, install the necessary Javascript libraries using npm:

$ cd $DUCKUMENTS
$ npm install MathJax-node jsdom@9.3 less

Troubleshooting nodejs installation problems

🔗

The only pain point in the installation procedure has been the installation of nodejs packages using npm. For some reason, they cannot be installed globally (npm install -g).

Do not use sudo for installation. It will cause problems.

If you use sudo, you probably have to delete a bunch of directories, such as: ~/duckuments/node_modules, ~/.npm, and ~/.node_modules, if they exist.

Installing Prince

🔗

Install PrinceXML from this page.

Installing fonts

🔗

Copy the ~/duckuments/fonts directory in ~/.fonts:

$ mkdir -p ~/.fonts    # create if not exists
$ cp -R ~/duckuments/fonts ~/.fonts

and then rebuild the font cache using:

$ fc-cache -fv

Compiling the PDF

🔗

To compile the PDF, use:

$ make compile-pdf

This creates the file:

./duckuments-dist/master/duckiebook.pdf
Because of mathjax bug

Features of the documentation writing system

🔗

The Duckiebook is written in a Markdown dialect. A subset of LaTeX is supported.

There are also some additional features that make it possible to create publication-worthy materials.

Markdown

🔗

The Duckiebook is written in a Markdown dialect.

Embedded LaTeX

🔗

You can use $\LaTeX$ math, environment, and references. For example, take a look at

$$ x^2 = \int_0^t f(\tau)\ \text{d}\tau $$

or refer to Proposition 1.

Proposition example This is an example proposition: $2x = x + x$.

The above was written as in Listing 1.


You can use $\LaTeX$ math, environment, and references.
For example, take a look at

\[
    x^2 = \int_0^t f(\tau)\ \text{d}\tau
\]

or refer to [](#prop:example).

\begin{proposition}[Proposition example]\label{prop:example}
This is an example proposition: $2x = x + x$.
\end{proposition}

Use of LaTeX code.

For the LaTeX environments to work properly you must add a \label declaration inside. Moreover, the label must have a prefix that is adequate to the environment. For example, for a proposition, you must insert \label{prop:name} inside.

The following table shows the list of the LaTeX environments supported and the label prefix that they need.

LaTeX environments and label prefixes
definition def:name
proposition prop:name
remark rem:name
problem prob:name
theorem thm:name
lemma lem:name

Examples of all environments follow.

<div id='def:lorem' class="definition latex_env" markdown="1">Lorem</div>

Lorem

<div id='prop:lorem' class="proposition latex_env" markdown="1">Lorem</div>

Lorem

<div id='rem:lorem' class="remark latex_env" markdown="1">Lorem</div>

Lorem

<div id='prob:lorem' class="problem latex_env" markdown="1">Lorem</div>

Lorem

<div id='exa:lorem' class="example latex_env" markdown="1">Lorem</div>

Lorem

<div id='thm:lorem' class="theorem latex_env" markdown="1">Lorem</div>

Lorem

<div id='lem:lorem' class="lemma latex_env" markdown="1">Lorem</div>

Lorem

I can also refer to all of them:
[](#def:lorem),
[](#prop:lorem),
[](#rem:lorem),
[](#prob:lorem),
[](#exa:lorem),
[](#thm:lorem),
[](#lem:lorem).

I can also refer to all of them: Definition 1, Proposition 2, Remark 1, Problem 1, Example 1, Theorem 1, Lemma 1.

LaTeX equations

🔗

We can refer to equations, such as \eqref{eq:one}:

\begin{equation} 2a = a + a \label{eq:one}\tag{1} \end{equation}

This uses align and contains \eqref{eq:two} and \eqref{eq:three}.

\begin{align} a &= b \label{eq:two}\tag{2} \\ &= c \label{eq:three}\tag{3} \end{align}


We can refer to equations, such as \eqref{eq:one}:

\begin{equation}
    2a = a + a          \label{eq:one}
\end{equation}

This uses `align` and contains  \eqref{eq:two} and \eqref{eq:three}.

\begin{align}
    a &= b       \label{eq:two} \\
      &= c       \label{eq:three}
\end{align}

Note that referring to the equations is done using the syntax \eqref{eq:name}, rather than [](#eq:name).

other LaTeX features supported

LaTeX symbols

🔗

The LaTeX symbols definitions are in a file called docs/symbols.tex.

Put all definitions there; if they are centralized it is easier to check that they are coherent.

Variables in command lines and command output

🔗

Use the syntax “![name]” for describing the variables in the code.

For example, to obtain:

$ ssh robot name.local

Use the following:


For example, to obtain:

    $ ssh ![robot name].local


Make sure to quote (with 4 spaces) all command lines. Otherwise, the dollar symbol confuses the LaTeX interpreter.

Character escapes

🔗

Use the string &#36; to write the dollar symbol $, otherwise it gets confused with LaTeX math materials. Also notice that you should probably use “USD” to refer to U.S. dollars.

Other symbols to escape are shown in Table 2.

Symbols to escape
use &#36; instead of $
use &#96; instead of `
use &#lt; instead of <
use &#gt; instead of >

Keyboard keys

🔗

Use the kbd element for keystrokes.

For example, to obtain:

Press a then Ctrl-C.

use the following:

Press <kbd>a</kbd> then <kbd>Ctrl</kbd>-<kbd>C</kbd>.

Figures

🔗

For any element, adding an attribute called figure-id with value fig:figure ID or tab:table ID will create a figure that wraps the element.

For example:

<div figure-id="fig:figure ID">
    figure content
</div>

It will create HMTL of the form:

<div id='fig:code-wrap' class='generated-figure-wrap'>
    <figure id='fig:figure ID' class='generated-figure'>
        <div>
            figure content
        </div>
    </figure>
</div>

To add a caption, add an attribute figure-caption:

<div figure-id="fig:figure ID" figure-caption="This is my caption">
    figure content
</div>

Alternatively, you can put anywhere an element figcaption with ID figure id:caption:

<element figure-id="fig:figure ID">
    figure content
</element>

<figcaption id='fig:figure ID:caption'>
    This the caption figure.
</figcaption>

To refer to the figure, use an empty link:

Please see [](#fig:figure ID).

The code will put a reference to “Figure XX”.

Subfigures

🔗

You can also create subfigures, using the following syntax.

<div figure-id="fig:big">
    <figcaption>Caption of big figure</figcaption>

    <div figure-id="subfig:first">
        <figcaption>Caption 1</figcaption>
        <p>Content of first subfig</p>
    </div>

    <div figure-id="subfig:second">
        <figcaption>Caption 2</figcaption>
        <p>Content of second subfig</p>
    </div>
</div>

Content of first subfig

Caption 1

Content of second subfig

Caption 2
Caption of big figure

Shortcut for tables

🔗

The shortcuts col2, col3, col4, col5 are expanded in tables with 2, 3, 4 or 5 columns.

The following code:


<col2 figure-id="tab:mytable" figure-caption="My table">
    <span>A</span>
    <span>B</span>
    <span>C</span>
    <span>D</span>
</col2>

gives the following result:

My table
A B
C D

labels-row1 and labels-row1

🔗

Use the classes labels-row1 and labels-row1 to make pretty tables like the following.

labels-row1: the first row is the headers.

labels-col1: the first column is the headers.

Using class="labels-col1"
header A B C 1
header D E F 2
header G H I 3
Using class="labels-row1"
header A header B header C
D E F
G H I
1 2 3

Linking to documentation

🔗

Establishing names of headers

🔗

You give IDs to headers using the format:

### header title {#topic ID}

For example, for this subsection, we have used:

### Establishing names of headers {#establishing}

With this, we have given this header the ID “establishing”.

Linking from the documentation to the documentation

🔗

You can use the syntax:

[](#topic ID)

to refer to the header.

You can also use some slightly more complex syntax that also allows to link to only the name, only the number or both (Table 6).

Linking to the documentation from outside the documentation

🔗

You are encouraged to put links to the documentation from the code or scripts.

To do so, use links of the form:

http://purl.org/dth/topic ID

Here “dth” stands for “Duckietown Help”. This link will get redirected to the corresponding document on the website.

For example, you might have a script whose output is:

$ rosrun mypackage myscript
Error. I cannot find the scuderia file.
See: http://purl.org/dth/scuderia

When the user clicks on the link, they will be redirected to Section 113.2.

Embedding videos

🔗

It is possible to embed Vimeo videos in the documentation.

Do not upload the videos to your personal Vimeo account; they must all be posted to the Duckietown Engineering account.

This is the syntax:

<dtvideo src="vimeo:vimeo ID"/>

For example, this code:

<div figure-id="fig:example-embed">
    <figcaption>Cool Duckietown by night</figcaption>
    <dtvideo src="vimeo:152825632"/>
</div>

produces this result:

The video is at https://vimeo.com/152825632.

Cool Duckietown by night

Depending on the output media, the result will change:

  • On the online book, the result is that a player is embedded.
  • On the e-book version, the result is that a thumbnail is produced, with a link to the video;
  • On the dead-tree version, a thumbnail is produced with a QR code linking to the video (TODO).

Bibliography

🔗

You need to have installed bibtex2html.

The system supports Bibtex files.

Place *.bib files anywhere in the directory.

Then you can refer to them using the syntax:

[](#bib:bibtex ID)

For example:

Please see [](#bib:siciliano07handbook).

Will result in:

Please see [3].

move-here tag

🔗

If a file contains the tag move-here, the fragment pointed by the src attribute is moved at the place of the tag.

This is used for autogenerated documentation.

Syntax:

# Node `node`

<move-here src='#package-node-autogenerated'>

Comments

🔗

You can insert comments using the HTML syntax for comments: any text between “<!–” and “–>” is ignored.


# My section

<!-- this text is ignored -->

Let's start by...

Special paragraphs tags

🔗

The system supports parsing of some special paragraphs.

Note that some of these might be redundant.

For now, documenting what is implemented.

Todos, task markers

🔗
TODO: todo

todo

TOWRITE: towrite

towrite

Task: task

task

Assigned: assigned

assigned

Notes and remarks

🔗
Remark: remark

remark

Note: note

note

Symptom: symptom

symptom

Warning: warning

warning

Troubleshooting

🔗
Symptom: symptom

symptom

Resolution: resolution

resolution

Guidelines

🔗
Bad: bad

bad

Better: better

better

Questions and answers

🔗
Q: question

question

A: answer

answer

Authors, maintainers, point of contact

🔗
Maintainer: maintainer

maintainer

Author: author

author

Point of contact: point of contact

point of contact

Slack channel: slack channel

slack channel

References

🔗
See: see

see

Reference: reference

reference

Requires: requires

requires

Recommended: recommended
See also: see also

see also

Div environments

🔗

For these, note the rules:

  • You must include markdown="1".
  • There must be an empty line after the first div and before the closing /div.

Example usage

🔗
<div class='example-usage' markdown="1">

This is how you can use `rosbag`:

    $ rosbag play log.bag

</div>

This is how you can use rosbag:

$ rosbag play log.bag

Check

🔗
<div class='check' markdown="1">

Check that you didn't forget anything.

</div>

Check that you didn’t forget anything.

Requirements

🔗
<div class='requirements' markdown="1">

List of requirements at the beginning of setup chapter.

</div>

List of requirements at the beginning of setup chapter.

Referring to Github files

🔗

You can refer to files in the repository by using:

See [this file](github:org=org,repo=repo,path=path,branch=branch).

The available keys are:

  • org (required): organization name (e.g. duckietown);
  • repo (required): repository name (e.g. Software);
  • path (required): the filename. Can be just the file name or also include directories;
  • branch (optional) the repository branch; defaults to master;

For example, you can refer to the file pkg_name/src/subscriber_node.py by using the following syntax:

See [this file](github:org=duckietown,repo=Software,path=pkg_name/src/subscriber_node.py)

You can also refer to a particular line:

This is done using the following parameters:

  • from_text (optional): reference the first line containing the text;
  • from_line (optional): reference the line by number;

For example, you can refer to the line containing “Initialize” of pkg_name/src/subscriber_node.py by using the following syntax:

For example, you can refer to [the line containing "Initialize"][link2]
of `pkg_name/src/subscriber_node.py` by using the following syntax:

[link2]: github:org=duckietown,repo=Software,path=pkg_name/src/subscriber_node.py,from_text=Initialize

You can also reference a range of lines, using the parameters:

  • to_text (optional): references the final line, by text;
  • to_line (optional): references the final line, by number.

You cannot give from_text and from_line at the same time. You cannot give a to_... without the from_....

For example, this link refers to a range of lines: click it to see how Github highlights the lines from “Initialize” to “spin”.

This is the source of the previous paragraph:

For example, [this link refers to a range of lines][interval]: click it to see how Github highlights the lines from "Initialize" to "spin".

[interval]: github:org=duckietown,repo=Software,path=pkg_name/src/subscriber_node.py,from_text=Initialize,to_text=spin

Putting code from the repository in line

🔗

In addition to referencing the files, you can also copy the contents of a file inside the documentation.

This is done by using the tag display-file.

For example, you can put a copy of pkg_name/src/subscriber_node.py using:

<display-file src="github:org=duckietown,repo=Software,path=pkg_name/src/subscriber_node.py"/>

and the result is the following automatically generated listing:

#!/usr/bin/env python
import rospy
from std_msgs.msg import String #Imports msg

# Define callback function
def callback(msg):
    rospy.loginfo("I heard: %s" %(msg.data))

# Initialize the node with rospy
rospy.init_node('subscriber_node', anonymous=False)
# Create subscriber
subscriber = rospy.Subscriber("topic", String, callback)

rospy.spin() #Keeps the script for exiting
subscriber_node.py

If you use the from_text and to_text (or from_line and to_line), you can actually display part of a file. For example:

<display-file src="github:org=duckietown,repo=Software,path=pkg_name/src/subscriber_node.py,from_text=Initialize,to_text=spin"/>

creates the following automatically generated listing:

# Initialize the node with rospy
rospy.init_node('subscriber_node', anonymous=False)
# Create subscriber
subscriber = rospy.Subscriber("topic", String, callback)

rospy.spin() #Keeps the script for exiting
subscriber_node.py
Because of mathjax bug

Documentation style guide

🔗

This chapter describes the conventions for writing the technical documentation.

General guidelines for technical writing

🔗

The following holds for all technical writing.

  • The documentation is written in correct English.

  • Do not say “should” when you mean “must”. “Must” and “should” have precise meanings and they are not interchangeable. These meanings are explained in this document.

  • “Please” is unnecessary in technical documentation.

“Please remove the SD card.”

“Remove the SD card”.

  • Do not use colloquialisms or abbreviations.

“The pwd is ubuntu.”

“The password is ubuntu.”

“To create a ROS pkg…”

“To create a ROS package…”

  • Python is capitalized when used as a name.

“If you are using python…”

“If you are using Python…”

  • Do not use emojis.

  • Do not use ALL CAPS.

  • Make infrequent use of bold statements.

  • Do not use exclamation points.

Style guide for the Duckietown documentation

🔗
  • It’s ok to use “it’s” instead of “it is”, “can’t” instead of “cannot”, etc.

  • All the filenames and commands must be enclosed in code blocks using Markdown backticks.

“Edit the ~/.ssh/config file using vi.”

“Edit the ~/.ssh/config file using vi.”

  • Ctrl-C, ssh etc. are not verbs.

Ctrl-C from the command line”.

“Use Ctrl-C from the command line”.

  • Subtle humor and puns about duckies are encouraged.

Writing command lines

🔗

Use either “laptop” or “duckiebot” (not capitalized, as a hostname) as the prefix for the command line.

For example, for a command that is supposed to run on the laptop, use:

laptop $ cd ~/duckietown

It will become:

laptop $ cd ~/duckietown

For a command that must run on the Duckiebot, use:

duckiebot $ cd ~/duckietown

It will become:

duckiebot $ cd ~/duckietown

If the command is supposed to be run on both, omit the hostname:

$ cd ~/duckietown

Frequently misspelled words

🔗
  • “Duckiebot” is always capitalized.

  • Use “Raspberry Pi”, not “PI”, “raspi”, etc.

  • These are other words frequently misspelled:

    5 GHz WiFi

Other conventions

🔗

When the user must edit a file, just say: “edit /this/file”.

Writing down the command line for editing, like the following:

$ vi /this/file

is too much detail.

(If people need to be told how to edit a file, Duckietown is too advanced for them.)

Troubleshooting sections

🔗

Write the documentation as if every step succeeds.

Then, at the end, make a “Troubleshooting” section.

Organize the troubleshooting section as a list of symptom/resolution.

The following is an example of a troubleshooting section.

Troubleshooting

🔗

This strange thing happens.

Maybe the camera is not inserted correctly. Remove and reconnect.

This other strange thing happens.

Maybe the plumbus is not working correctly. Try reformatting the plumbus.

Because of mathjax bug

Knowledge graph

🔗

This chapter describes something that is not implemented yet.

Formalization

🔗

Atoms

🔗

Atom An atom is a concrete resource (text, video) that is the smallest unit that is individually addressable. It is indivisible.

Each atom as a type, as follows:

text
  text/theory
  text/setup
  text/demo
  text/exercise
  text/reference
  text/instructor-guide
  text/quiz
video
  video/lecture
  video/instructable
  video/screencast
  video/demo

Semantic graph of atoms

🔗

Atoms form a directed graph, called “semantic graph”.

Each node is an atom.

The graph has four different types of edges:

  • Requires” edges describe a strong dependency: “You need to have done this. Otherwise it will not work.”
  • Recommended” edges describe a weaker dependency; it is not strictly necessary to have done that other thing, but it will significantly improve the result of this.
  • Reference” edges describe background information. “If you don’t know / don’t remember, you might want to see this”
  • See also” edges describe interesting materials for the interested reader. Completely optional; it will not impact the result of the current procedure.

Modules

🔗

A “module” is an abstraction from the point of view of the teacher.

Module A module is a directed graph, where the nodes are either atoms or other modules, and the edges can be of the four types described in Subsection 9.1.2.

Because modules can contain other modules, they allow to describe hierarchical contents. For example, a class module is a module that contains other modules; a “degree” is a module that contains “class” modules, etc.

Modules can overlap. For example, a “Basic Object Detection” and an “Advanced Object Detection” module might have a few atoms in common.

Atoms properties

🔗

Each atom has the following properties:

  • An ID (alphanumeric + - and ‘_’). The ID is used for cross-referencing. It is the same in all languages.
  • A type, as above.

There might be different versions of each atom. This is used primarily for dealing with translations of texts, different representations of the same image, Powerpoint vs Keynote, etc.

A version is a tuple of attributes.

The attributes are:

  • Language: A language code, such as en-US (default), zh-CN, etc.

  • Mime type: a MIME type.

Each atom version has:

  • A status value: one of draft, beta, ready, to-update (Table 7).
  • A human-readable title.
  • A human-readable summary (1 short paragraph).
Status codes
draft We just started working on it, and it is not ready for public consumption.
beta Early reviewers should look at it now.
ready The document is ready for everybody.
to-update A new pass is needed on this document, because it is not up to date anymore.

Markdown format for text-like atoms

🔗

For the text-like resources, they are described in Markdown files.

The name of the file does not matter.

All files are encoded in UTF-8.

Each file starts with a H1 header. The contents is the title.

The header has the following attributes:

  1. The ID. ({#ID})
  2. The language is given by an attribute lang ({lang=en-US}).
  3. The type is given by an attribute type ({type=demo}).
  4. The status is given by an attribute status ({status=draft}).

Here is an example of a header with all the attributes:

# Odometry calibration {#odometry-calibration lang=en-US type='text/theory' status=ready}

This first paragraph will be used as the "summary" for this text.

calibration.en.md

And this is how the Italian translation would look like:

# Calibrazione dell'odometria {#odometry-calibration lang=it type='text/theory' status=draft}

Questo paragrafo sarà usato come un sommario del testo.

calibration.it.md

How to describe the semantic graphs of atoms

🔗

In the text, you describe the semantic graph using tags and IDs.

In Markdown, you can give IDs to sections using the syntax:

# Setup step 1  {#setup-step1}

This is the first setup step.

Then, when you write the second step, you can add a a semantic edge using the following.

# Setup step 2  {#setup-step2}

This is the second setup step.

Requires: You have completed the first step in [](#setup-step1).

The following table describes the syntax for the different types of semantic links:

How to describe modules

🔗

Define a micro-format for this.

Because of mathjax bug

Translations

🔗

This part is not implemented yet.

File organization

🔗

Translations are organized file-by-file.

For every file name.md, name the translated file name.language code.md, where the language code is one of the standard codes, and put it in the same directory.

For example, these could be a set of files, including a Chinese (simplified), italian, and Spanish translation:

representations.md
representations.zh-CN.md
representations.it.md
representations.es.md

The reason is that in this way you can check automatically from Git whether representations.zh-CN.md is up to date or representations.md has been modified since.

Guidelines for English writers

🔗

Here are some considerations for the writers of the original version, to make the translators’ job easier.

It is better to keep files smallish so that (1) the translation tasks can feel approachable by translators; (2) it is easier for the system to reason about the files.

Name all the headers with short, easy identifiers, and never change them.

File format

🔗

All files are assumed to be encoded in UTF-8.

The header IDs should not be translated and should remain exactly the same. This will allow keeping track of the different translations.

For example, if this is the original version:

# Robot uprising {#robot-uprising}

Hopefully it will never happen.

Then the translated version should be:

# La rivolta dei robot {#robot-uprising}

Speriamo che non succeda.
Because of mathjax bug

Operation manual - Duckiebot

🔗
Because of mathjax bug

Duckiebot configurations

🔗

Here we define the different Duckiebot hardware configurations, and describe their functionalities. This is a good starting point if you are wondering what parts you should purchase to get started. Once you have decided which configuration best suits your needs, you can proceed to purchasing the components for a C0+wjd or C1 Duckiebot.

Configuration list

🔗
  • Configuration C0: Only camera and motors.

  • Configuration C0+w: C0, plus an additional wireless adapter.

  • Configuration C0+j: C0, plus an additional wireless joypad for remote control.

  • Configuration C0+d: C0, plus an additional USB drive.

  • Configuration C1: C0+wjd, plus LEDs and bumpers.

Configuration functionality

🔗

C0

🔗

This is the minimal configuration for a Duckiebot. It will be able to navigate a Duckietown, but not communicate with other Duckiebots. It is the configuration of choice for tight budgets or when operation of a single Duckiebot is more of interest than fleet behaviours.

Insert pic of assembled Duckiebot in C0 configuration.

C0+w

🔗

In this configuration, the minimal C0 version is augmented with a 5 GHz wireless adapter, which drastically improves connectivity. This feature is particularly useful in connection saturated enviroments, e.g., classrooms.

Insert pic of assembled Duckiebot in C0+w configuration.

C0+j

🔗

In this configuration, the minimal C0 version is augmented with a 2.4 GHz wireless joypad, used for manual remote control of the Duckiebot. It is particularly useful for getting the Duckiebot our of tight spots or letting younger ones have a drive.

Insert pic of assembled Duckiebot in C0+j configuration.

C0+d

🔗

In this configuration, the minimal C0 version is augmented with a USB flash hard drive. This drive is convenient for storing videos (logs) as it provides both extra capacity and faster data transfer rates than the microSD card in the Raspberry Pi. Moreover, it is easy to unplug it from the Duckiebot at the end of teh day and bring it over to a computer for downloading and analyzing stored data.

Insert pic of assembled Duckiebot in C0+d configuration.

C0+wjd

🔗

The upgrades of the minimal C0 version are not mutually exclusive. We will refer to C0+wjd when any or all of the add-ons to the minimal version are considered.

Insert pic of assembled Duckiebot in C0+wjd configuration.

C1

🔗

This is the ultimate Duckiebot configuration and it includes the necessary hardware for controlling and placing 5 RGB LEDs on the Duckiebot. It is the necessary configuration to enable communication between Duckiebots, hence fleet behaviours (e.g., negotiating crossing an intersection).

Insert pic of assembled Duckiebot in C1 configuration.

Because of mathjax bug

Acquiring the parts for the Duckiebot C0

🔗

The trip begins with acquiring the parts. Here, we provide a link to all bits and pieces that are needed to build a Duckiebot, along with their price tag. If you are wondering what is the difference between different Duckiebot configurations, read this.

In general, keep in mind that:

  • The links might expire, or the prices might vary.
  • Shipping times and fees vary, and are not included in the prices shown below.
  • Substitutions are OK for the mechanical components, and not OK for all the electronics, unless you are OK in writing some software.
  • Buying the parts for more than one Duckiebot makes each one cheaper than buying only one.

Cost: USD 159 + Shipping Fees (minimal configuration C0)

Time: 15 days (average shipping for cheapest choice of components)

Results: A kit of parts ready to be assembled in a C0 or C0+wjd configuration.

Next Steps:

  • After receiving these components, you are ready to do some soldering before assembling your C0 or C0+wjd Duckiebot.

Add a different “Tools” section in the table (e.g., solderer), or add in the resoruces beginning snippet; Differentiate pricing for bulk vs detail purchase (?)

Bill of materials

🔗

Bill of materials
Chassis USD 20
Camera with 160-FOV Fisheye Lens USD 22
Camera Mount USD 8.50
300mm Camera Cable USD 2
Raspberry Pi 3 - Model B USD 35
Heat Sinks USD 5
Power supply for Raspberry Pi USD 7.50
16 GB Class 10 MicroSD Card USD 10
Mirco SD card reader USD 6
Stepper Motor HAT USD 22.50
Stacking Header USD 2.50/piece
Battery USD 20
16 Nylon Standoffs (M2.5 12mm F 6mm M USD 0.05/piece
4 Nylon Hex Nuts (M2.5) USD 0.02/piece
4 Nylon Screws (M2.5x10) USD 0.05/piece
2 Zip Ties (300x5mm) USD 9
Wireless Adapter (5 GHz) (C0+w) USD 20
Joypad (C0+j) USD 10.50
Tiny 32GB USB Flash Drive (C0+d) USD 12.50
Total for C0 configuration USD 159
Total for C0+w configuration USD 179
Total for C0+j configuration USD 169.50
Total for C0+d configuration USD 171.50
Total for C0+wjd configuration USD 212

Chassis

🔗

We selected the Magician Chassis as the basic chassis for the robot (Figure 12).

We chose it because it has a double-decker configuration, and so we can put the battery in the lower part.

The chassis pack includes the motors and wheels as well as the structural part.

The Magician Chassis

Raspberry Pi 3 - Model B

🔗

The Raspberry Pi is the central computer of the Duckiebot. Duckiebots use Model B (Figure 13) (A1.2GHz 64-bit quad-core ARMv8 CPU, 1GB RAM), a small but powerful computer.

The Raspberry Pi 3 Model B

The price for this in the US is about USD 35.

Power Supply

🔗

We want a hard-wired power source (5VDC, 2.4A, Micro USB) to supply the Raspberry Pi (Figure 14).

The Power Supply

The price for this in the US is about USD 5-10.

Heat Sinks

🔗

The Raspberry Pi will heat up significantly during use. It is warmly recommended to add heat sinks, as in Figure 15. Since we will be stacking HATs on top of the Raspberry Pi with 15 mm standoffs, the maximum height of the heat sinks should be well below 15 mm. The chip dimensions are 15x15mm and 10x10mm.

The Heat Sinks

Class 10 MicroSD Card

🔗

The MicroSD card (Figure 16) is the hard disk of the Raspberry Pi. 16 Gigabytes of capacity are sufficient for the system image.

The MicroSD card

Mirco SD card reader

🔗

A microSD card reader (Figure 17) is useful to copy the system image to a Duckiebot from a computer to the Raspberry Pi microSD card, when the computer does not have a native SD card slot.

The Mirco SD card reader

Camera

🔗

The Camera is the main sensor of the Duckiebot. All versions equip a 5 Mega Pixels 1080p camera with wide field of view ($160^\circ$) fisheye lens (Figure 18).

The Camera with Fisheye Lens

Camera Mount

🔗

The camera mount (Figure 19) serves to keep the camera looking forward at the right angle to the road (looking slightly down). The front cover is not essential.

The Camera Mount

300mm Camera Cable

🔗

A longer (300 mm) camera cable Figure 20 make assembling the Duckiebot easier, allowing for more freedom in the relative positioning of camera and computational stack.

A 300 mm camera cable for the Raspberry Pi

DC Stepper Motor HAT

🔗

We use the DC Stepper motor HAT (Figure 27) to control the DC motors that drive the wheels. This item will require soldering to be functional.

The Stepper Motor HAT

Stacking Headers

🔗

We use a long 20x2 stacking header (Figure 22) to connect the Raspberry Pi with the DC Stepper Motor HAT. This item will require soldering to be functional.

The Stacking Headers

Battery

🔗

The battery (Figure 23) provides power to the Duckiebot.

We choose this battery because it has a good combination of size (to fit in the lower deck of the Magician Chassis), high output amperage (2.4A and 2.1A at 5V DC) over two USB outputs, a good capacity (10400 mAh) at an affordable price.

The Battery

Standoffs, Nuts and Screws

🔗

We use non electrically conductive standoffs (M2.5 12mm F 6mm M), nuts (M2.5), and screws (M2.5x10mm) to hold the Raspberry Pi to the chassis and the HATs stacked on top of the Raspberry Pi.

The Duckiebot requires 8 standoffs, 4 nuts and 4 screws.

Standoffs, Nuts and Screws

Zip Tie

🔗

Two 300x5mm zip ties are needed to keep the battery at the lower deck from moving around.

The zip ties

Configuration C0-w

🔗

Wireless Adapter (5 GHz)

🔗

The Edimax AC1200 EW-7822ULC 5 GHz wireless adpater (Figure 26) boosts the connectivity of the Duckiebot, especially useful in busy Duckietowns (e.g., classroom).

The Edimax AC1200 EW-7822ULC wifi adapter

Configuration C0-j

🔗

Joypad

🔗

The joypad is used to manually remote control the Duckiebot. Any 2.4 GHz wireless controller (with a tiny USB dongle) will do.

The model linked in the table (Figure 27) does not include batteries.

2 AA 1.5V batteries.

A Wireless Joypad

Add figure with 2 AA batteries

Configuration C0-d

🔗

Tiny 32GB USB Flash Drive

🔗

Iin configuration C0+d, the Duckiebot is equppied with a “external” hard drive (Figure 28). This add-on is very convenient to store logs during experiments and later port them to a workstation for analysis. It provides storage capacity and faster data transfer than the MicroSD card.

The Tiny 32GB USB Flash Drive
Because of mathjax bug

Soldering boards for C0

🔗

Shiying

Resources necessary:

Duckiebot C0+wjd parts. The acquisition process is explained in Chapter 12. The configurations are described in Chapter 11.

Time: ??? minutes

Results:

finish above

Because of mathjax bug

Preparing the power cable for C0

🔗

In configuration C0 we will need a cable to power the DC motor HAT from the battery. The keen observer might have noticed that such a cable was not included in the C0 Duckiebot parts chapter. Here, we create this cable by splitting open any USB-A cable, identifying and stripping the power wires, and using them to power the DC motor HAT. If you are unsure about the definitions of the different Duckiebot configurations, read Chapter 11.

It is important to note that these instructions are relevant only for assembling a C0+wjd configuration Duckiebot. If you intend to build a C1 configuration Duckiebot, you can skip these instructions.

Resources necessary:

One male USB-A to anything cable.

A pair of scissors.

A multimeter (only if you are not purchasing the suggested components)

Time: 5 minutes

Results: One male USB-A to wires power cable

Step 1: Find a cable

🔗

To begin with, find a male USB-A to anything cable.

If you have purchased the suggested components listed in Chapter 12, you can use the longer USB cable contained inside the battery package (Figure 29), which will be used as an example in these instructions.

The two USB cables in the suggested battery pack.

Put the shorter cable back in the box, and open the longer cable (Figure 30)

Take the longer cable, and put the shorter on back in the box.

Step 2: Cut the cable

🔗

Make sure the USB cable is unplugged from any power source before proceeding.

Take the scissors and cut it (Figure 31) at the desired length from the USB-A port.

Cut the USB cable using the scissors.

The cut will look like in Figure 32.

A cut USB cable.

Step 3: Strip the cable

🔗

Paying attention not to get hurt, strip the external white plastic. A way to do so without damaging the wires is shown in Figure 33.

Stripping the external layer of the USB cable.

After removing the external plastic, you will see four wires: black, green, white and red (Figure 34).

Under the hood of a USB-A cable.

Once the bottom part of the external cable is removed, you will have isolated the four wires (Figure 35).

The four wires inside a USB-A cable.

Step 3: Strip the wires

🔗

Make sure the USB cable is unplugged from any power source before proceeding.

Once you have isolated the wires, strip them, and use the scissors to cut off the data wires (green and white, central positions) (Figure 36).

Strip the power wires and cut the data wires.

If you are not using the suggested cable, or want to verify which are the data and power wires, continue reading.

Step 4: Find the power wires

🔗

If you are using the USB-A cable from the suggested battery pack, black and red are the power wires and green and white are instead for data.

If you are using a different USB cable, or are curious to verify that black and red actually are the power cables, take a multimeter and continue reading.

Plug the USB port inside a power source, e.g., the Duckiebot’s battery. You can use some scotch tape to keep the cable from moving while probing the different pairs of wires with a multimeter. The voltage across the pair of power cables will be roughly twice the voltage between a power and data cable. The pair of data cables will have no voltage differential across them. If you are using the suggested Duckiebot battery as power source, you will measure around 5V across the power cables (Figure 37).

Finding which two wires are for power.

Step 5: Test correct operation

🔗

You are now ready to secure the power wires to the DC motor HAT power pins. To do so though, you need to have soldered the boards first. If you have not done so yet, read Chapter 13.

If you have soldered the boards already, you may test correct functionality of the newly crafted cable. Connect the battery with the DC motor HAT by making sure you plug the black wire in the pin labeled with a minus: - and the red wire to the plus: + (Figure 38).

Connnect the power wires to the DC motor HAT

If the green LED turns on, the DC motor HAT is receving power.

Because of mathjax bug

Assembling the Duckiebot C0

🔗

Shiying

Duckiebot C0+wjd parts. The acquisition process is explained in Chapter 12.

Having soldered the C0+wjd parts. The soldering process is explained in Chapter 13.

Having prepared the power cable. The power cable preparation is explained in Chapter 14.

Time: about ??? minutes.

estimate time.

Results: An assembled Duckiebot in configuration C0+wjd.

Shiying: here will be the instruction about assembling the Duckiebot.

Because of mathjax bug

Reproducing the image

🔗

Andrea

These are the instructions to reproduce the Ubuntu image that we use.

Please note that the image is already available, so you don’t need to do this manually.

However, this documentation might be useful if you would like to port the software to a different distribution.

Resources necessaries:

Internet connection to download the packages.

A PC running any Linux with an SD card reader.

Time: about 20 minutes.

Results:

  • A baseline Ubuntu Mate 16.04.2 image with updated software.

Download and uncompress the Ubuntu Mate image

🔗

Download the image from the page

https://ubuntu-mate.org/download/

The file we are looking for is:

filename: ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz
    size: 1.2 GB
  SHA256: dc3afcad68a5de3ba683dc30d2093a3b5b3cd6b2c16c0b5de8d50fede78f75c2

After download, run the command sha256sum to make sure you have the right version:

laptop $ sha256sum ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz
dc3afcad68a5de3ba683dc30d2093a3b5b3cd6b2c16c0b5de8d50fede78f75c2

If the string does not correspond exactly, your download was corrupted. Delete the file and try again.

Then decompress using the command xz:

laptop $ xz -d ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz

Burn the image to an SD card

🔗

Next, burn the image on to the SD card.

This procedure is explained in Section 98.2.

Verify that the SD card was created correctly

🔗

Remove the SD card and plug it in again in the laptop.

Ubuntu will mount two partitions, by the name of PI_ROOT and PI_BOOT.

Installation

🔗

Boot the disk in the Raspberry Pi.

Choose the following options:

language: English
username: ubuntu
password: ubuntu
hostname: duckiebot

Choose the option to log in automatically.

Reboot.

Update installed software

🔗

The WiFi was connected to airport network duckietown with password quackquack.

Afterwards I upgraded all the software preinstalled with these commands:

duckiebot $ sudo apt update
duckiebot $ sudo apt dist-upgrade

Expect dist-upgrade to take quite a long time (up to 2 hours).

Raspberry Pi Config

🔗

The Raspberry Pi is not accessible by SSH by default.

Run raspi-config:

duckiebot $ sudo raspi-config

choose “3. Interfacing Options”, and enable SSH,

We need to enable the camera and the I2C bus.

choose “3. Interfacing Options”, and enable camera, and I2C.

Also disable the graphical boot

Install packages

🔗

Install these packages.

Etckeeper:

duckiebot $ sudo apt install etckeeper

Editors / shells:

duckiebot $ sudo apt install -y vim emacs byobu zsh

Git:

duckiebot $ sudo apt install -y git git-extras

Other:

duckiebot $ sudo apt install htop atop nethogs iftop
duckiebot $ sudo apt install aptitude apt-file

Development:

duckiebot $ sudo apt install -y build-essential libblas-dev liblapack-dev libatlas-base-dev gfortran libyaml-cpp-dev

Python:

duckiebot $ sudo apt install -y python-dev ipython python-sklearn python-smbus
duckiebot $ sudo apt install -y python-termcolor
duckiebot $ sudo pip install scipy --upgrade

I2C:

duckiebot $ sudo apt install -y i2c-tools

Install Edimax driver

🔗

First, mark the kernel packages as not upgradeable:

$ sudo apt-mark hold raspberrypi-kernel raspberrypi-kernel-headers
raspberrypi-kernel set on hold.
raspberrypi-kernel-headers set on hold

Then, download and install the Edimax driver from this repository.

$ git clone git@github.com:duckietown/rtl8822bu.git
$ cd rtl8822bu
$ make
$ sudo make install

Install ROS

🔗

Install ROS.

The procedure is given in Section 110.1.

Wireless configuration (old version)

🔗

This is the old version.

There are two files that are important to edit.

The file /etc/network/interfaces should look like this:

# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
#source-directory /etc/network/interfaces.d

auto wlan0

# The loopback network interface
auto lo
iface lo inet loopback

# Wireless network interface
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

The file /etc/wpa_supplicant/wpa_supplicant.conf should look like this:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
ssid="duckietown"
psk="quackquack"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
auth_alg=OPEN
}
network={
   key_mgmt=NONE
}

Wireless configuration

🔗

The files that describe the network configuration are in the directory

/etc/NetworkManager/system-connections/

This is the contents of the connection file duckietown, which describes how to connect to the duckietown wireless network:

[connection]
id=duckietown
uuid=e9cef1bd-f6fb-4c5b-93cf-cca837ec35f2
type=wifi
permissions=
secondaries=
timestamp=1502254646

[wifi]
mac-address-blacklist=
mac-address-randomization=0
mode=infrastructure
ssid=duckietown

[wifi-security]
group=
key-mgmt=wpa-psk
pairwise=
proto=
psk=quackquack

[ipv4]
dns-search=
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
ip6-privacy=0
method=auto

This is the file

/etc/NetworkManager/system-connections/create-5ghz-network

Contents:

[connection]
id=create-5ghz-network
uuid=7331d1e7-2cdf-4047-b426-c170ecc16f51
type=wifi
# Put the Edimax interface name here:
interface-name=wlx74da38c9caa0 - to change
permissions=
secondaries=
timestamp=1502023843

[wifi]
band=a
# Put the Edimax MAC address here
mac-address=74:DA:38:C9:CA:A0 - to change
mac-address-blacklist=
mac-address-randomization=0
mode=ap
seen-bssids=
ssid=duckiebot-not-configured

[ipv4]
dns-search=
method=shared

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
ip6-privacy=0
method=ignore

Note that there is an interface name and MAC address that need to be changed on each PI.

SSH server config

🔗

This enables the SSH server:

$ sudo systemctl enable ssh

Create swap Space

🔗

Do the following:

Create an empty file using the dd (device-to-device copy) command:

duckiebot $ sudo dd if=/dev/zero of=/swap0 bs=1M count=512

This is for a 512 MB swap space.

Format the file for use as swap:

duckiebot $ sudo mkswap /swap0

Add the swap file to the system configuration:

duckiebot $ sudo vi /etc/fstab

Add this line to the bottom:

/swap0 swap swap

Activate the swap space:

duckiebot $ sudo swapon -a

Passwordless sudo

🔗

First, make vi the default editor, using

$ sudo update-alternatives --config editor

and then choose vim.basic.

Then run:

$ sudo visudo

And then change this line:

%sudo   ALL=(ALL:ALL) ALL

into this line:

%sudo   ALL=(ALL:ALL) NOPASSWD:ALL

Clean up

🔗

You can use the command dpigs to find out which packages take lots of space.

$ sudo apt install wajig  debian-goodies

Either:

$ wajig large
$ dpigs -H -n 20

Stuff to remove:

$ sudo apt remove thunderbird
$ sudo apt remove libreoffice-\*
$ sudo apt remove openjdk-8-jre-headless
$ sudo apt remove fonts-noto-cjk
$ sudo apt remove brasero

At the end, remove extra dependencies:

$ sudo apt autoremove

And remove the apt cache using:

$ sudo apt clean

The total size should be around 6.6GB.

Ubuntu user configuration

🔗

Groups

🔗

You should make the ubuntu user belong to the i2c and input groups:

duckiebot $ sudo adduser ubuntu i2c
duckiebot $ sudo adduser ubuntu input

: forgot to add to aug20 image:

duckiebot $ sudo adduser ubuntu video

You may need to do the following (but might be done already through raspi-config):

duckiebot $ sudo udevadm trigger

Basic SSH config

🔗

Do the basic SSH config.

The procedure is documented in Section 100.3.

this is not in the aug10 image.

Passwordless SSH config

🔗

Add .authorized_keys so that we can all do passwordless SSH.

The key is at the URL

https://www.dropbox.com/s/pxyou3qy1p8m4d0/duckietown_key1.pub?dl=1

Download to .ssh/authorized_keys:

duckiebot $ curl -o .ssh/authorized_keys URL above

Shell prompt

🔗

Add the following lines to ~ubuntu/.bashrc:

echo ""
echo "Welcome to a duckiebot!"
echo ""
echo "Reminders:"
echo ""
echo "1) Do not use the user 'ubuntu' for development - create your own user."
echo "2) Change the name of the robot from 'duckiebot' to something else."
echo ""

export EDITOR=vim

Check that all required packages were installed

🔗

At this point, before you copy/distribute the image, create a user, install the software, and make sure that what-the-duck does not complain about any missing package.

(Ignore what-the-duck‘s errors about things that are not set up yet, like users.)

Creating the image

🔗

You may now want to create an image that you can share with your friends. They will think you are cool because they won’t have to duplicate all of the work that you just did. Luckily this is easy. Just power down the duckiebot with:

duckiebot $ sudo shutdown -h now

and put the SD card back in your laptop.

The procedure of how to burn an image is explained in Section 98.2; except you will invert the if and of destinations.

You may want to subsequently shrink the image, for example if your friends have smaller SD cards than you.

The procedure of how to shrink an image is explained in Section 98.3.

Some additions since last image to add in the next image

🔗

Note here the additions since the last image was created.

Create a file

/etc/duckietown-image.yaml

Containing these lines

base: Ubuntu 16.04.2
date: DATE
comments: |
    any comments you have

So that we know which image is currently in used.

Install ntpdate:

$ sudo apt install ntpdate

We should install Git LFS on the Raspberry Pi, but so far AC did not have any luck. See Section 108.1.

Because of mathjax bug

Installing Ubuntu on laptops

🔗

Andrea

Before you prepare the Duckiebot, you need to have a laptop with Ubuntu installed.

A laptop with free disk space.

Internet connection to download the Ubuntu image.

About ??? minutes.

Results: A laptop ready to be used for Duckietown.

Install Ubuntu

🔗

Install Ubuntu 16.04.2.

For instructions, see for example this online tutorial.

On the choice of username: During the installation, create a user for yourself with a username different from ubuntu, which is the default. Otherwise, you may get confused later.

Install useful software

🔗

Use etckeeper to keep track of the configuration in /etc:

laptop $ sudo apt install etckeeper

Install ssh to login remotely and the server:

laptop $ sudo apt install ssh

Use byobu:

laptop $ sudo apt install byobu

Use vim:

laptop $ sudo apt install vim

Use htop to monitor CPU usage:

laptop $ sudo apt install htop

Additional utilities for git:

laptop $ sudo apt install git git-extras

Other utilities:

laptop $ sudo apt install avahi-utils ecryptfs-utils

Install ROS

🔗

Install ROS on your laptop.

The procedure is given in Section 110.1.

Other suggested software

🔗

Redshift

🔗

This is Flux for Linux. It is an accessibility/lab safety issue: bright screens damage eyes and perturb sleep [4].

Install redshift and run it.

laptop $ sudo apt install redshift-gtk

Set to “autostart” from the icon.

Installation of the duckuments system

🔗

Optional but very encouraged: install the duckuments system. This will allow you to have a local copy of the documentation and easily submit questions and changes.

The procedure is documented in Section 6.4.

Passwordless sudo

🔗

Set up passwordless sudo.

This procedure is described in Section 16.11.

SSH and Git setup

🔗

Basic SSH config

🔗

Do the basic SSH config.

The procedure is documented in Section 100.3.

Create key pair for username

🔗

Next, create a private/public key pair for the user; call it username@robot name.

The procedure is documented in Section 100.5.

Add username‘s public key to Github

🔗

Add the public key to your Github account.

The procedure is documented in Section 109.3.

If the step is done correctly, this command should succeed:

duckiebot $ ssh -T git@github.com

Local Git setup

🔗

Set up Git locally.

The procedure is described in Section 107.3.

Because of mathjax bug

Duckiebot Initialization

🔗

Andrea

An SD card of dimensions at least ??? GB.

A computer with an internet connection, an SD card reader, and 35 GB of free space.

An assembled Duckiebot in configuration D17-C0. This is the result of Chapter 15.

Results: A Duckiebot that is ready to use.

What does it mean “ready to use”?.

Acquire and burn the image

🔗

On the laptop, download the compressed image at this URL:

https://www.dropbox.com/s/1p4am7erdd9e53r/duckiebot-RPI3-AC-aug10.img.xz?dl=1

The size is 2.5 GB.

You can use:

$ curl -o duckiebot-RPI3-AC-aug10.img.xz URL above

Uncompress the file:

$ xz -d -k duckiebot-RPI3-AC-aug10.img.xz

This will create a file of 32 GB in size.

To make sure that the image is downloaded correctly, compute its hash using the program sha256sum:

$ sha256sum duckiebot-RPI3-AC-aug10.img
2ea79b0fc6353361063c89977417fc5e8fde70611e8afa5cbf2d3a166d57e8cf  duckiebot-ac-aug10.img

Compare the hash that you obtain with the hash above. If they are different, there was some problem in downloading the image.

Next, burn the image on disk.

The procedure of how to burn an image is explained in Section 98.2.

Turn on the Duckiebot

🔗

Put the SD Card in the Duckiebot.

Turn on the Duckiebot by connecting the power cable to the battery.

Add figure

Connect the Duckiebot to a network

🔗

You can login to the Duckiebot in two ways:

  1. Through an Ethernet cable.
  2. Through a duckietown WiFi network.

In the worst case, you can use an HDMI monitor and a USB keyboard.

Option 1: Ethernet cable

🔗

Connect the Duckiebot and your laptop to the same network switch.

Allow 30 s - 1 minute for the DHCP to work.

Option 2: Duckietown network

🔗

The Duckiebot connects automatically to a 2.4 GHz network called “duckietown” and password “quackquack”.

Connect your laptop to the same wireless network.

Ping the Duckiebot

🔗

To test that the Duckiebot is connected, try to ping it.

The hostname of a freshly-installed duckiebot is duckiebot-not-configured:

laptop $ ping duckiebot-not-configured.local

You should see output similar to the following:

PING duckiebot-not-configured.local (X.X.X.X): 56 data bytes
64 bytes from X.X.X.X: icmp_seq=0 ttl=64 time=2.164 ms
64 bytes from X.X.X.X: icmp_seq=1 ttl=64 time=2.303 ms
...

SSH to the Duckiebot

🔗

Next, try to log in using SSH, with account ubuntu:

laptop $ ssh ubuntu@duckiebot-not-configured.local

The password is ubuntu.

By default, the robot boots into Byobu.

Please see Chapter 106 for an introduction to Byobu.

Not sure it’s a good idea to boot into Byobu.

(For D17-C1) Configure the robot-generated network

🔗

D17-0+w The Duckiebot in configuration D17-C0+w can create a WiFi network.

It is a 5 GHz network; this means that you need to have a 5 GHz WiFi adapter in your laptop.

First, make sure that the Edimax is correctly installed. Using iwconfig, you should see four interfaces:

duckiebot $ iwconfig
wlxAABBCCDDEEFFGG  unassociated  Nickname:"rtl8822bu"

...

lo        no wireless extensions.

enxb827eb1f81a4  no wireless extensions.

wlan1     IEEE 802.11bgn  ESSID:"duckietown"

...

Make note of the name wlxAABBCCDDEEFFGG.

Look up the MAC address using the command:

duckiebot $ ifconfig wlxAABBCCDDEEFFGG
wlx74da38c9caa0 Link encap:Ethernet  HWaddr AA:BB:CC:DD:EE:FF:GG

Then, edit the connection file

/etc/NetworkManager/system-connections/create-5ghz-network

Make the following changes:

  • Where it says interface-name=..., put “wlxAABBCCDDEEFFGG”.
  • Where it says mac-address=..., put “AA:BB:CC:DD:EE:FF:GG”.
  • Where it says ssid=duckiebot-not-configured, put “ssid=robot name”.

Reboot.

At this point you should see a new network being created named “robot name”.

You can connect with the laptop to that network.

If the Raspberry Pi’s network interface is connected to the duckietown network and to the internet, the Raspberry Pi will act as a bridge to the internet.

Setting up wireless network configuration

🔗

This part should not be necessary anymore

The Duckiebot is configured by default to connect to a wireless network with SSID duckietown. If that is not your SSID then you will need to change the configuration.

You can add a new network by editing the file:

/etc/wpa_supplicant/wpa_supplicant.conf

You will see a block like the following:

network={
 ssid="duckietown"
 scan_ssid=1
 psk="quackquack"
 priority=10
}

Add a new one with your SSID and password.

This assumes you have a roughly similar wireless network setup - if not then you might need to change some of the other attributes.

Update the system

🔗

Next, we need to update to bring the system up to date.

Use these commands

duckiebot $ sudo apt update
duckiebot $ sudo apt dist-upgrade

Give a name to the Duckiebot

🔗

It is now time to give a name to the Duckiebot.

These are the criteria:

  • It should be a simple alphabetic string (no numbers or other characters like “-”, “_”, etc.) .
  • It will always appear lowercase.
  • It cannot be a generic name like “duckiebot”, “robot” or similar.

From here on, we will refer to this string as “robot name”. Every time you see robot name, you should substitute the name that you chose.

Change the hostname

🔗

We will put the robot name in configuration files.

Files in /etc are only writable by root, so you need to use sudo to edit them. For example:

duckiebot $ sudo vi filename

Edit the file

/etc/hostname

and put “robot name” instead of duckiebot-not-configured.

Also edit the file

/etc/hosts

and put “robot name” where duckiebot-not-configured appears.

The first two lines of /etc/hosts should be:

127.0.0.1   localhost
127.0.1.1   robot name

there is a command hostname that promises to change the hostname. However, the change given by that command does not persist across reboots. You need to edit the files above for the changes to persist.

Never add other hostnames in /etc/hosts. It is a tempting fix when DNS does not work, but it will cause other problems subsequently.

Then reboot the Raspberry Pi using the command

$ sudo reboot

After reboot, log in again, and run the command hostname to check that the change has persisted:

$ hostname
robot name

Expand your filesystem

🔗

If your SD card is larger than the image, you’ll want to expand the filesystem on your robot so that you can use all of the space available. Achieve this with:

duckiebot $ sudo raspi-config --expand-rootfs

and then reboot

duckiebot $ sudo shutdown -r now

once rebooted you can test whether this was successful by doing

duckiebot $ df -lh

the output should give you something like:

Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  7.8G   21G  28% /
devtmpfs        427M     0  427M   0% /dev
tmpfs           432M  316K  431M   1% /dev/shm
tmpfs           432M   12M  420M   3% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           432M     0  432M   0% /sys/fs/cgroup
/dev/mmcblk0p1   63M   21M   43M  34% /boot
tmpfs            87M   24K   87M   1% /run/user/1000
/dev/sda1        29G  5.3G   24G  19% /media/ubuntu/44A7-9E91

You should see that the Size of your /dev/sda1 partition is “close” to the side of your SD card.

Create your user

🔗

You must not use the ubuntu user for development. Instead, you need to create a new user.

Choose a user name, which we will refer to as username.

To create a new user:

duckiebot $ sudo useradd -m username

Make the user an administrator by adding it to the group sudo:

duckiebot $ sudo adduser username sudo

Make the user a member of the group input and i2c

duckiebot $ sudo adduser username input
duckiebot $ sudo adduser username video
duckiebot $ sudo adduser username i2c

Set the shell bash:

duckiebot $ sudo chsh -s /bin/bash andrea

To set a password, use:

duckiebot $ sudo passwd username

At this point, you should be able to login to the new user from the laptop using the password:

laptop $ ssh username@robot name

Next, you should repeat some steps that we already described.

Basic SSH config

🔗

Do the basic SSH config.

The procedure is documented in Section 100.3.

Create key pair for username

🔗

Next, create a private/public key pair for the user; call it username@robot name.

The procedure is documented in Section 100.5.

Add username‘s public key to Github

🔗

Add the public key to your Github account.

The procedure is documented in Section 109.3.

If the step is done correctly, this command should succeed:

duckiebot $ ssh -T git@github.com

Local Git configuration

🔗

This procedure is in Section 107.3.

Set up the laptop-Duckiebot connection

🔗

Make sure that you can login passwordlessly to your user from the laptop.

The procedure is explained in Section 100.6. In this case, we have: local = laptop, local-user = your local user on the laptop, remote = robot name, remote-user = username.

If the step is done correctly, you should be able to login from the laptop to the robot, without typing a password:

laptop $ ssh username@robot name

Some advice on the importance of passwordless access

🔗

In general, if you find yourself:

  • typing an IP
  • typing a password
  • typing ssh more than once
  • using a screen / USB keyboard

it means you should learn more about Linux and networks, and you are setting yourself up for failure.

Yes, you “can do without”, but with an additional 30 seconds of your time. The 30 seconds you are not saving every time are the difference between being productive roboticists and going crazy.

Really, it is impossible to do robotics when you have to think about IPs and passwords…

Other customizations

🔗

If you know what you are doing, you are welcome to install and use additional shells, but please keep Bash as be the default shell. This is important for ROS installation.

For the record, our favorite shell is ZSH with oh-my-zsh.

Hardware check: camera

🔗

Check that the camera is connected using this command:

duckiebot $ vcgencmd get_camera
supported=1 detected=1

If you see detected=0, it means that the hardware connection is not working.

You can test the camera right away using a command-line utility called raspistill.

Use the raspistill command to capture the file out.jpg:

duckiebot $ raspistill -t 1 -o out.jpg

Then download out.jpg to your computer using scp for inspection.

For instructions on how to use scp, see Subsection 102.1.1.

Troubleshooting

🔗

detected=0

If you see detected=0, it is likely that the camera is not connected correctly.

If you see an error that starts like this:

mmal: Cannot read camera info, keeping the defaults for OV5647
...
mmal: Camera is not detected. Please check carefully the camera module is installed correctly.

then, just like it says: “Please check carefully the camera module is installed correctly.”.

Because of mathjax bug

Software setup and RC remote control

🔗

Andrea

Laptop configured, according to Chapter 17.

You have configured the Duckiebot. The procedure is documented in Chapter 18.

You have created a Github account and configured public keys, both for the laptop and for the Duckiebot. The procedure is documented in Chapter 109.

Results: You can run the joystick demo.

Clone the Duckietown repository

🔗

Clone the repository in the directory ~/duckietown:

duckiebot $ git clone git@github.com:duckietown/Software.git ~/duckietown

For the above to succeed you should have a Github account already set up.

It should not ask for a password.

Troubleshooting

🔗

It asks for a password.

You missed some of the steps described in Chapter 109.

Other weird errors.

Probably the time is not set up correctly. Use ntpdate as above:

$ sudo ntpdate -u us.pool.ntp.org

Set up ROS environment on the Duckiebot

🔗

All the following commands should be run in the ~/duckietown directory:

duckiebot $ cd ~/duckietown

Now we are ready to make the workspace. First you need to source the baseline ROS environment:

duckiebot $ source /opt/ros/kinetic/setup.bash

Then, build the workspace using:

duckiebot $ catkin_make -C catkin_ws/

For more information about catkin_make, see Section 110.6.

there is a known bug, for which it fails the first time on the Raspberry Pi. Try again; it will work.

Add your vehicle to the scuderia file

🔗

Add your vehicle to the scuderia file.

Test that the joystick is detected

🔗

Plug the joystick receiver in one of the USB port on the Raspberry Pi.

To make sure that the joystick is detected, run:

duckiebot $ ls /dev/input/

and check if there is a device called js0 on the list.

Make sure that your user is in the group input and i2c:

duckiebot $ groups
username sudo input i2c

If input and i2c are not in the list, you missed a step. Ohi ohi! You are not following the instructions carefully!

Consult again Section 18.12.

To test whether or not the joystick itself is working properly, run:

duckiebot $ jstest /dev/input/js0

Move the joysticks and push the buttons. You should see the data displayed change according to your actions.

Run the joystick demo

🔗

SSH into the Raspberry Pi and run the following from the duckietown directory:

duckiebot $ cd ~/duckietown
duckiebot $ source environment.sh

The environment.sh setups the ROS environment at the terminal (so you can use commands like rosrun and roslaunch).

Now make sure the motor shield is connected.

Run the command:

duckiebot $ roslaunch duckietown joystick.launch veh:=robot name

If there is no “red” output in the command line then pushing the left joystick knob controls throttle - right controls steering.

This is the expected result of the commands:

left joystick up forward
left joystick down backward
right joystick left turn left (positive yaw)
right joystick right turn right (negative yaw)

It is possible you will have to unplug and replug the joystick or just push lots of buttons on your joystick until it wakes up. Also make sure that the mode switch on the top of your joystick is set to “X”, not “D”.

Is all of the above valid with the new joystick?

Close the program using Ctrl-C.

Troubleshooting

🔗

The robot moves weirdly (e.g. forward instead of backward).

The cables are not correctly inserted. Please refer to the assembly guide for pictures of the correct connections. Try swapping cables until you obtain the expected behavior.

Check that the joystick has the switch set to the position “x”.And the mode light should be off.

The left joystick does not work.

If the green light on the right to the “mode” button is on, click the “mode” button to turn the light off. The “mode” button toggles between left joystick or the cross on the left.

The robot does not move at all.

The cables are disconnected.

The program assumes that the joystick is at /dev/input/js0. In doubt, see Section 19.4.

The proper shutdown procedure for the Raspberry Pi

🔗

Generally speaking, you can terminate any roslaunch command with Ctrl-C.

To completely shutdown the robot, issue the following command:

duckiebot $ sudo shutdown -h now

Then wait 30 seconds.

If you disconnect the power before shutting down properly using shutdown, the system might get corrupted.

Then, disconnect the power cable, at the battery end.

If you disconnect frequently the cable at the Raspberry Pi’s end, you might damage the port.

Because of mathjax bug

Reading from the camera

🔗

You have configured the Duckiebot. The procedure is documented in Chapter 18.

You know the basics of ROS (launch files, roslaunch, topics, rostopic).

put reference

Results: You know that the camera works under ROS.

Check the camera hardware

🔗

It might be useful to do a quick camera hardware check.

The procedure is documented in Section 18.14.

Create two windows

🔗

On the laptop, create two Byobu windows.

A quick reference about Byobu commands is in Chapter 106.

You will use the two windows as follows:

  • In the first window, you will launch the nodes that control the camera.
  • In the second window, you will launch programs to monitor the data flow.

You could also use multiple terminals instead of one terminal with multiple Byobu windows. However, using Byobu is the best practice to learn.

First window: launch the camera nodes

🔗

In the first window, we will launch the nodes that control the camera.

Activate ROS:

duckiebot $ source environment.sh

Run the launch file called camera.launch:

duckiebot $ roslaunch duckietown camera.launch veh:=robot name

At this point, you should see the red LED on the camera light up continuously.

In the terminal you should not see any red message, but only happy messages like the following:

...
[INFO] [1502539383.948237]: [/robot name/camera_node] Initialized.
[INFO] [1502539383.951123]: [/robot name/camera_node] Start capturing.
[INFO] [1502539384.040615]: [/robot name/camera_node] Published the first image.

For more information about roslaunch and “launch files”, see Section 110.3.

Second window: view published topics

🔗

Switch to the second window.

Activate the ROS environment:

duckiebot $ source environment.sh

List topics

🔗

You can see a list of published topics with the command:

duckiebot $ rostopic list

For more information about rostopic, see Section 110.5.

You should see the following topics:

/robot name/camera_node/camera_info
/robot name/camera_node/image/compressed
/robot name/camera_node/image/raw
/rosout
/rosout_agg

Show topics frequency

🔗

You can use rostopic hz to see the statistics about the publishing frequency:

laptop $ rostopic hz /robot name/camera_node/image/compressed

On a Raspberry Pi 3, you should see a number close to 30 Hz:

average rate: 30.016
    min: 0.026s max: 0.045s std dev: 0.00190s window: 841

Show topics data

🔗

You can view the messages in real time with the command rostopic echo:

laptop $ rostopic echo /robot name/camera_node/image/compressed

You should see a large sequence of numbers being printed to your terminal.

That’s the “image” — as seen by a machine.

If you are Neo, then this already makes sense. If you are not Neo, in Chapter 22, you will learn how to visualize the image stream on the laptop using rviz.

use Ctrl-C to stop rostopic.

Because of mathjax bug

RC control launched remotely

🔗

Andrea

You can run the joystick demo from the Raspberry Pi. The procedure is documented in Chapter 19.

Results: You can run the joystick demo from your laptop.

Two ways to launch a program

🔗

ROS nodes can be launched in two ways:

  1. “local launch”: log in to the Raspberry Pi using SSH and run the program from there.
  2. “remote launch”: run the program directly from a laptop.

Which is better when is a long discussion that will be done later. Here we set up the “remote launch”.

draw diagrams

Download and setup Software repository on the laptop

🔗

As you did on the Duckiebot, you should clone the Software repository in the ~/duckietown directory.

The procedure is documented in Section 19.1.

Then, you should build the repository.

This procedure is documented in Section 19.2.

Edit the machines files on your laptop

🔗

You have to edit the machines files on your laptop, as you did on the Duckiebot.

The procedure is documented in Section 19.3.

Start the demo

🔗

Now you are ready to launch the joystick demo remotely.

Make sure that you can login with SSH without a password. From the laptop, run:

laptop $ ssh username@robot name.local

If this doesn’t work, you missed some previous steps.

Run this on the laptop:

laptop $ source environment.sh
laptop $ roslaunch duckietown joystick.launch veh:=robot name

You should be able to drive the vehicle with joystick just like the last example. Note that remotely launching nodes from your laptop doesn’t mean that the nodes are running on your laptop. They are still running on the Raspberry Pi in this case.

For more information about roslaunch, see Section 110.3.

Watch the program output using rqt_console

🔗

Also, you might have notice that the terminal where you launch the launch file is not printing all the printouts like the previous example. This is one of the limitation of remote launch.

Don’t worry though, we can still see the printouts using rqt_console.

On the laptop, open a new terminal window, and run:

laptop $ export ROS_MASTER_URI=http://robot name.local:11311/
laptop $ rqt_console

AC: I could not see any messages in rqt_console - not sure what is wrong.

You should see a nice interface listing all the printouts in real time, completed with filters that can help you find that message you are looking for in a sea of messages.

You can use Ctrl-C at the terminal where roslaunch was executed to stop all the nodes launched by the launch file.

For more information about rqt_console, see Section 110.2.

Troubleshooting

🔗

roslaunch fails with an error similar to the following:

remote[robot name.local-0]: failed to launch on robot name:

Unable to establish ssh connection to [username@robot name.local:22]:
Server u'robot name.local' not found in known_hosts.

You have not followed the instructions that told you to add the HostKeyAlgorithms option. Delete ~/.ssh/known_hosts and fix your configuration.

The procedure is documented in Section 100.3.

Because of mathjax bug

RC+camera remotely

🔗

Andrea

You can run the joystick demo remotely. The procedure is documented in Chapter 21.

You can read the camera data from ROS. The procedure is documented in Chapter 20.

You know how to get around in Byobu. You can find the Byobu tutorial in Chapter 106.

Results: You can run the joystick demo from your laptop and see the camera image on the laptop.

Assumptions

🔗

We are assuming that the joystick demo in Chapter 21 worked.

We are assuming that the procedure in Chapter 20 succeeded.

We also assume that you terminated all instances of roslaunch with Ctrl-C, so that currently there is nothing running in any window.

Terminal setup

🔗

On the laptop, this time create four Byobu windows.

A quick reference about Byobu commands is in Chapter 106.

You will use the four windows as follows:

  • In the first window, you will run the joystick demo, as before.
  • In the second window, you will launch the nodes that control the camera.
  • In the third window, you will launch programs to monitor the data flow.
  • In the fourth window, you will use rviz to see the camera image.

Add figures

First window: launch the joystick demo

🔗

In the first window, launch the joystick remotely using the same procedure in Section 21.4.

laptop $ source environment.sh
laptop $ roslaunch duckietown joystick.launch veh:=robot name

You should be able to drive the robot with the joystick at this point.

Second window: launch the camera nodes

🔗

In the second window, we will launch the nodes that control the camera.

The launch file is called camera.launch:

laptop $ source environment.sh
laptop $ roslaunch duckietown camera.launch veh:=robot name

You should see the red led on the camera light up.

Third window: view data flow

🔗

Open a third terminal on the laptop.

You can see a list of topics currently on the ROS_MASTER with the commands:

laptop $ source environment.sh
laptop $ export ROS_MASTER_URI=http://robot name.local:11311/
laptop $ rostopic list

You should see the following:

/diagnostics
/robot name/camera_node/camera_info
/robot name/camera_node/image/compressed
/robot name/camera_node/image/raw
/robot name/joy
/robot name/wheels_driver_node/wheels_cmd
/rosout
/rosout_agg

Fourth window: visualize the image using rviz

🔗

Launch rviz by using these commands:

laptop $ source environment.sh
laptop $ source set_ros_master.sh robot name
laptop $ rviz

For more information about rviz, see Section 110.4.

In the rviz interface, click “Add” on the lower left, then the “By topic” tag, then select the “Image” topic by the name

/robot name/camera_node/image/compressed

Then click “ok”. You should be able to see a live stream of the image from the camera.

Proper shutdown procedure

🔗

To stop the nodes: You can stop the node by pressing Ctrl-C on the terminal where roslaunch was executed. In this case, you can use Ctrl-C in the terminal where you launched the camera.launch.

You should see the red light on the camera turn off in a few seconds.

Note that the joystick.launch is still up and running, so you can still drive the vehicle with the joystick.

Because of mathjax bug

Interlude: Ergonomics

🔗

Andrea

So far, we have been spelling out all commands for you, to make sure that you understand what is going on.

Now, we will tell you about some shortcuts that you can use to save some time.

in the future you will have to debug problems, and these problems might be harder to understand if you rely blindly on the shortcuts.

Time: ??? minutes.

Results: You will know about some useful shortcuts.

set_ros_master.sh

🔗

Instead of using:

$ export ROS_MASTER_URI=http://robot name.local:11311/

You can use the “set_ros_master.sh” script in the repo:

$ source set_ros_master.sh robot name

Note that you need to use source; without that, it will not work.

SSH aliases

🔗

Instead of using

$ ssh username@robot name.local

You can set up SSH so that you can use:

$ ssh my-robot

To do this, create a host section in ~/.ssh/config with the following contents:

Host my-robot
    User username
    Hostname robot name.local

Here, you can choose any other string in place of “my-robot”.

Note that you cannot do

$ ping my-robot

You haven’t created another hostname, just an alias for SSH.

However, you can use the alias with all the tools that rely on SSH, including rsync and scp.

Because of mathjax bug

Wheel calibration

🔗

Andrea

Because of mathjax bug

Camera calibration

🔗
Because of mathjax bug

Taking a log

🔗

Andrea

Because of mathjax bug

Operation manual - Duckietowns

🔗
Because of mathjax bug

Duckietown parts

🔗

Duckietowns are the cities where Duckiebots drive. Here, we provide a link to all bits and pieces that are needed to build a Duckietown, along with their price tag. Note that while the topography of the map is highly customable, we recommend using the components listed below. Before purchasing components for a Duckietown, read Chapter 31 to understand how Duckietowns are built.

In general, keep in mind that:

  • The links might expire, or the prices might vary.
  • Shipping times and fees vary, and are not included in the prices shown below.
  • Substitutions are probably not OK, unless you are OK in writing some software.

Cost (per $m^2$): USD ??? + Shipping Fees

Time: ??? days (average shipping time)

Results: A kit of parts ready to be assembled in a Duckietown.

Next Steps: Assemblying a Duckietown.

Figure out costs

Bill of materials

🔗

Bill of materials for Duckietown
Duckies USD 17/100 pieces
Floor Mats USD 37.5/6 pieces (24 sqft)
Duct tape - Red USD 8.50/roll
Duct tape - White USD 8.50/roll
Duct tape - Yellow USD 8/roll
Traffic signs USD 18.50/13 pieces
Total for $\text{Duckietown}/m^2$ USD ??

Add suggestions for “small”, “medium”, “big” towns as a function of $m^2$ and supported bots

Duckies

🔗

Duckies (Figure 39) are essential yet non functional.

The Duckies

Floor Mats

🔗

The floor mats (Figure 40) are the ground on which the Duckiebots drive.

We choose these mats because they have desirable surface properties, are modular, and have the right size to be street segments. Each square is (~61x61cm) and can connect on every side of other squares. There are 6 mats in each package.

The Floor Mats

Each mat can be a segment of road: straight, a curve, or an intersection (3, or 4 way). To design your Duckietown, see Chapter 31.

Duck Tape

🔗

We use duck (duct) tape of different colors (Figure 41) for defining the roads and their signals. White indicates the road boundaries, yellow determines lane boundaries and red are stop signs.

The white and red tape we use are 2 inches wide, while the yellow one is 1 inch wide.

The Duck Tapes

To verify how much tape you need for each road segment type, see Chapter 31.

Traffic Signs

🔗

Traffic signs (Figure 42) inform Duckiebots on the map of Duckietown, allowing them to make driving decisions.

The Signs

Depending on the chose road topograhy, the number of necessary road signal will vary. To design your Duckietown, see Chapter 31.

Because of mathjax bug

Traffic lights Parts

🔗

Traffic lights regulate intersections in Duckietown. Here, we provide a link to all bits and pieces that are needed to build a traffic light, along with their price tag. You will need one traffic per either three, or four way intersections. The components listed below meet the appearence specifications described in Chapter 31.

In general, keep in mind that:

  • The links might expire, or the prices might vary.
  • Shipping times and fees vary, and are not included in the prices shown below.
  • Substitutions are probably OK, if you are willing to write some software.

Cost: USD ?? + Shipping Fees

Time: ?? days (average shipping time)

Results: A kit of parts ready to be assembled in a traffic light.

Next Steps: - Assemblying a traffic light.

Estimate time and costs

Bill of materials

🔗

Bill of materials for traffic light
Raspberry Pi USD ??
4 LEDs USD ??
Wires USD ??
Total for Traffic Light USD ??

Complete table

Raspberry Pi

🔗

(Figure 43) are essential yet non functional.

The placeholder
Because of mathjax bug

Duckietown Assembly

🔗

Shiying

Because of mathjax bug

Traffic lights Assembly

🔗

Shiying

Because of mathjax bug

The Duckietown specification

🔗

Liam?

Topology

🔗

Topology constraints

🔗

Signs placement

🔗
Because of mathjax bug

Operation manual - Duckiebot with LEDs

🔗
Because of mathjax bug

Acquiring the parts for the Duckiebot C1

🔗

Upgrading your C0+wjd configuration to C1 starts here, with purchasing the necessary components. We provide a link to all bits and pieces that are needed to build a C1 Duckiebot, along with their price tag. If you are wondering what is the difference between different Duckiebot configurations, read Chapter 11.

In general, keep in mind that:

  • The links might expire, or the prices might vary.
  • Shipping times and fees vary, and are not included in the prices shown below.
  • Buying the parts for more than one Duckiebot makes each one cheaper than buying only one.
  • A few components in this configuration are custom designed, and might be trickier to obtain.

Requires: - A Duckiebot in C0+wjd configuration. - Cost: USD 77 + Bumpers manufacturing solution - Time: 21 Days (LED board manufacturing and shipping time)

Results: - A kit of parts ready to be assembled in a C1 configuration Duckiebot.

Next Steps: - After receiving these components, you are ready to do some soldering before assembling your C1 Duckiebot.

Bill of materials

🔗

Bill of materials
LEDs USD 10
LED HAT USD 28.20 for 3 pieces
Power Cable USD 7.80
20 Female-Female Jumper Wires (300mm) USD 8
Male-Male Jumper Wire (150mm) USD 1.95
PWM/Servo HAT USD 17.50
Bumpers TBD (custom made)
40 pin female header USD 1.50
5 4 pin female header USD 0.60/piece
2 16 pin male header USD 0.61/piece
12 pin male header USD 0.48/piece
3 pin male header USD 0.10/piece
2 pin female shunt jumper USD 2/piece
5 200 Ohm resistors USD 0.10/piece
10 130 Ohm resistors USD 0.10/piece
Total for C0+wjd configuration USD 212
Total for C1 components USD 77 + Bumpers
Total for C1 configuration USD 299+Bumpers

add links to Bumpers: (a) bumper design files; (b) one-click purchasing option (?)

LEDs

🔗

The Duckiebot is equipped with 5 RGB LEDs (Figure 44). LEDs can be used to signal to other Duckiebots, or just make fancy patterns.

The pack of LEDs linked in the table above holds 10 LEDs, enough for two Duckiebots.

The RGB LEDs

LED HAT

🔗

The LED HAT (Figure 45) provides an interface for our RGB LEDs and the computational stack. This board is a daughterboard for the Adafruit 16-Channel PWM/Servo HAT, and enables connection with additional gadgets such as ADS1015 12 Bit 4 Channel ADC, Monochrome 128x32 I2C OLED graphic display, and Adafruit 9-DOF IMU Breakout - L3GD20H+LSM303. This item will require soldering.

This board is custom degined and can only be ordered in minimum runs of 3 pieces. The price scales down quickly with quantity, and lead times may be significant, so it is better to buy these boards in bulk.

The LED HAT

PWM/Servo HAT

🔗

The PWM/Servo HAT (Figure 46) mates to the LED HAT and provides the signals to control the LEDs, without taking computational resources away from the Rasperry Pi itself. This item will require soldering.

The PWM-Servo HAT

Power Cable

🔗

To power the PWM/Servo HAT from the battery, we use a short (30cm) angled male USB-A to 5.5/2.1mm DC power jack cable (Figure 47).

The 30cm angled USB to 5.5/2.1mm power jack cable.

Male-Male Jumper Wires

🔗

The Duckiebot needs one male-male jumper wire (Figure 48) to power the DC Stepper Motor HAT from the PWM/Servo HAT.

Premier Male-Male Jumper Wires

Female-Female Jumper Wires

🔗

20 Female-Female Jumper Wires (Figure 49) are necessary to connect 5 LEDs to the LED HAT.

Premier Female-Female Jumper Wires

Bumpers

🔗

These bumpers are designed to keep the LEDs in place and are therefore used only in configuration C1. They are custom designed parts, so they must be produced and cannot be bought. We used laser cutting facilities. Our design files are available [here].

add links to .sldprt files once confirmed final version

The Bumpers

Headers, resistors and jumper

🔗

Upgrading C0+wjd to C1 requires several electrical bits: 5 of 4 pin female header, 2 of 16 pin male headers, 1 of 12 pin male header, 1 of 3 pin male header, 1 of 2 pin female shunt jumper, 5 of 200 Ohm resistors and finally 10 of 130 Ohm resistors.

These items require soldering.

The Headers
The Resistors

Missing figures.

Because of mathjax bug

Soldering boards for C1

🔗

Shiying

Resources necessary:

- Duckiebot C1 parts. The acquisition process is explained in Chapter 32. The configurations are described in Chapter 11.

- Time: ??? minutes

Results:

finish above

Because of mathjax bug

Assembling the Duckiebot C1

🔗

Shiying

Duckiebot C1 parts. The acquisition process is explained in Chapter 32.

Soldering C1 parts. The soldering process is explained in Chapter 33.

Time: about ??? minutes.

estimate time.

Results:

  • An assembled Duckiebot in configuration C1.

Shiying: here will be the instruction about assembling the Duckiebot.

Because of mathjax bug

C1 (LEDs) setup

🔗

Andrea

Because of mathjax bug

Theory chapters

🔗

These are the theory chapters.

Because of mathjax bug

Chapter template

🔗

Theory chapters benefit from a standardized exposition. Here, we define the template for these chapters. Rememeber to check Chapter 7 for a comprehensive and up-to-date list of Duckiebook supported features.

Example Title: PID control

🔗

Start with a brief introduction of the discussed topic, describing its place in the bigger picture, justifying the reading constraints/guidelines below. Write it as if the reader knew the relevant terminology. For example:

PID control is the simplest approach to making a system behave in a desired way rather than how it would naturally behave. It is simple because the measured output is directly feedbacked, as opposed to, e.g., the system’s states. The control signal is obtained as a weighted sum of the tracking error (Proportional term), its integral over time (Integrative term) and its instantaneous derivative (Derivative term), from which the appellative of PID control. The tracking error is defined as the instantaneous difference between a reference and a measured system output.

Knowledge necessary:

Required Reading: Insert here a list of topics and suggested resources related to necessary knowledge in order to understand the content presented. Example:

Terminology: autonomy overview

Suggested Reading: Insert here a list of topics and suggested resources related to recommended knowledge in order to better understand the content presented. Example:

Problem Definition

🔗

In this section we crisply define the problem object of this chapter. It serves as a very brief recap of exactly what is needed from previous atoms as well. E.g.

Let:

\begin{align} \dot{\state}_t = A\state_t+Bu_t \\ y = C\state_t+Du_t \label{eq:system}\tag{1} \end{align}

be the LTI model of the Duckiebot’s plant, with $x \in \statesp$, $y \in \mathbb{R}^p$ and $u \in \mathbb{R}^m$. We recall (Duckiebot Modeling) that:

\begin{align} A &= \left[ \begin{array}{ccc} a_{11} & \dots & a_{1n} \\ \vdots & \ddots & \vdots \\ a_{n1} & \dots & a_{nn} \end{array} \right] \\ B &= \left[ b_1 \,\, \dots \,\, b_m \right]^T \\ C &= \left[ c_1 \ \,\, \dots \,\, c_p \right] \\ D &= 0. \end{align}

[…]

Remember you can use the problem environment of $\LaTeX$ to formally state a problem:

PID Given a system \eqref{eq:system} and measurements of the output $\tilde{y}_t = y_t + n_t, n_t \textasciitilde \cal{N}(0,\sigma)$, find a set of PID coefficients that meet the specified requirements for: - stability, - performance, - robustness.

as shown in (Figure 53).

A classical block diagram for PID control. We like to use a lot of clear figures in the Duckiebook.

Introduced Notions

🔗

Section 1: title-1 (e.g.: Definitions)

🔗

Reference signals A reference signal $\tilde{y}_t \in \mathcal{L}_2(\mathcal{T})$ is …

Definition 4 is very important.

Insert ‘random’ checks to keep the reader’s attention up:

if you can’t be woken up in the middle of the night and rememeber the definition of $\mathcal{L}_2(\cdot)$, read: [5]

Another definition Lorem

Section 2: title-2 (e.g.: Output feedback)

🔗

Now that we know what we’re talking about, lets get in the meat of the problem. Here is what is happening:

$$ \cal{Lorem} $$

Section 3: title-3 (e.g.: Tuning the controller)

🔗

Introduce the ‘synthesis through attempts’ methodology (a.k.a. tweak until death)

Section 4: title-4 (e.g.: Performance Metrics)

🔗

How do we know if the PID controller designed above is doing well? We need to define some performance metrics first:

Overshoot, Module at resonance, Settling Time, Rising Time

[…]

This is a ‘think about it’ interrupt, used as attention grabber:

When a Duckiebot ‘overshoots’, it means that […] and the following will happen […].

Section N: title-N (e.g.: Saving the world with PID)

🔗

And finally, this is how you save the world, in theory.

Examples

🔗

This section serves as a collection of theoretical and practical examples that can clarify part or all of the above.

Theoretical Examples

🔗

More academic examples

T-Example 1

🔗

Immagine a spring-mass-damper system…

T-Example M

🔗

[…]

Implementation Examples

🔗

More Duckiebot related examples

I-Example 1

🔗

I-Example M

🔗

[…]

Pointers to Exercises

🔗

Here we just add references to the suggested exercises, defined in the appropriate exercise chapters.

Conclusions

🔗
  • What did we do? (recap)
  • What did we find? (analysis)
  • Why is it useful? (synthesis)
  • Final Conclusions (what have we learned)

Next Steps

🔗

Strong of this new knowledge (what have we learned), we can now […].

Further Reading: insert here reference resources for the interested reader:

learn all there is to know about PID: [5]

become a linear algebra master: Matrix cookbook

References

🔗

Do not include a reference chapter. References are automatically compiled to the Bibliography Section.

Jacopo Maintainer: Jacopo Point of Contact: Jacopo

Because of mathjax bug

Symbols and conventions

🔗

Andrea

Conventions

🔗

If $x$ is a function of time, use $x_t$ rather than $x(t)$.

Consider the function $x(t)$.

Consider the function $x_t$.

Table of symbols

🔗

Here are some useful symbols.

Spaces
command result
\SOthree $\SOthree$ Rotation matrices
\SEthree $\SEthree$ Euclidean group
\SEtwo $\SEtwo$ Euclidean group
\setwo $\setwo$ Euclidean group algebra

States and poses:

Poses and states
command result
\pose $\pose_t \in \SEtwo$ Pose of the robot in the plane
\state_t \in \statesp $\state_t \in \statesp$ System state (includes the pose, and everything else)
Because of mathjax bug

Linear algebra

🔗

This Section is work in progress.

Jacopo

Linear algebra provides the set of mathematical tools to (a) study linear relationships and (b) describe linear spaces. It is a field of mathematics with important ramifications.

Linearity is an important concept because it is powerful in describing the input-output behaviour of many natural phenomena (or systems). As a matter of fact, all those systems that cannot be modeled as linear, still can be approximated as linear to gain an intuition, and sometimes much more, of what is going on.

So, in a way or the other, linear algebra is a starting point for investigating the world around us, and Duckietown is no exception.

Knowledge necessary:

Real numbers are complex for you?: Number theory addref

$\forall$ is a typo for A and $\in$ are Euros? Mathematical symbolic language: addref

find appropriate references and fill in above

Problem Definition

🔗

In this section we discuss vectors, matrices and linear spaces, along with their properties. Before introducing the these arguments, we need to formally define what we mean by linearity. The word linear comes from the latin linearis, which means pertaining to or resembling a line. You should recall that a line is represented by an equation like $y = mx + q$, but here we intend linearity as a property of maps, so there is a little more to linearity than lines (although lines are linear maps indeed). To avoid confusions, let us translate the concept of linearity in mathematical language.

First, let us define a function, as a mapping between sets.

Set A set $\mathbb{X} = \{x_1, x_2, \dots\}$ is a well-defined collection of distinct elements, or members of the set, $x_i$, $i = 1, 2, \dots$. For the time being, we assume elements to (complex) numbers.

Function A function $f : \mathbb{X} \rightarrow \mathbb{Y}$ is a mapping between the sets $\mathbb{X}$ and $\mathbb{Y}$. For every input element $x \in \mathbb{X}$, the mapping will produce an output $y = f(x) \in \mathbb{Y}$.

add references

Linearity A function $f: \mathbb{X} \rightarrow \mathbb{Y}$ is linear when, $\forall x_i \in \mathbb{X}$, $i = \{1,2\}$, and $\forall a \in \mathbb{R}$:

\begin{align} f(ax_1) &= af(x_1), \label{eq:lin1}\tag{1} \quad \text{and:} \\ f(x_1 + x_2) &= f(x_1) + f(x_2) \label{eq:lin2}\tag{2} \end{align}

Condition \eqref{eq:lin1} is referred to as the property of homogeneity (of order 1), while condition \eqref{eq:lin2} is referred to as additivity.

Superposition Principle Conditions \eqref{eq:lin1} and \eqref{eq:lin2} can be merged to express the same meaning through: \begin{align} f(ax_1 + bx_2) = af(x_1) + bf(x_2), \forall x_i \in \mathbb{X}, i = \{1,2\}, \forall a,b \in \mathbb{R} \label{eq:linearity}\tag{3}. \end{align}

This equivalent condition \eqref{eq:linearity} is instead referred to as superposition principle, which unveils the bottom line of the concept of linearity: adding up (equivalently, scaling up) inputs results in an added up (equivalently, scaled up) output.

Vectors

🔗

Let $n$ belong to the set of natural numbers $\mathbb{N}$, i.e., $n \in \mathbb{N}$, and let $a_i \in \mathbb{R}$, $i = \{1, \dots, n\}$ be real coefficients. While $\mathbb{R}$ is the set of real numbers, $\mathbb{R}^n$ is the set of all $n$-tuples of real numbers.

Vector and components

An $n$-dimensional $\textit{vector}$ is an $n$-tuple:

\begin{align} \label{eq:vector}\tag{4} \textbf{v} = \left[ \begin{array}{c} v_1 \\ \vdots \\ v_n \end{array} \right] \in \mathbb{R}^{n \times 1} \equiv \mathbb{R}^n, \end{align}

of components $v_1, \dots, v_n \in \mathbb{R}$.

You can immagine a vector as a “directional number”, or an arrow that starts a certain point and goes in a certain direction (in $\mathbb{R}^n$). In this representation, the number is the length of the arrow, or the modulus of the vector, and it can be derived through the vector’s components.

Length of a vector We define the length, or modulus, of a vector $\textbf{v} \in \mathbb{R}^n$ as:
\begin{align} \label{eq:vec2norm}\tag{5} \|\textbf{v}\| = \sqrt{v_1^2 + \dots + v_n^2} \in \mathbb{R}. \end{align}

2-norm Generally speaking, it is not always possible to define the length of a vector (addref). But when it is possible (e.g., Hilbert spaces), and in Duckietown it always is, there are many ways to define it. The most common and intuitive definition is the Euclidian- or 2-norm, which is defined above in \eqref{eq:vec2norm}.

  • Definition of:
  • norms
  • p-norm, $\infty$-norm
  • unit vector
A vector and its components.

Vector algebra

🔗
  • sum of vectors
  • dot product / inner product
  • cross product

Orthogonality between vectors

🔗

Matrices

🔗

Definitions:

  • matrix dimensions
  • flat and tall matrix
  • adjoint matrix
  • inverse matrix
  • rank of a matrix
  • condition number of a matrix (?)
  • identity matrix
  • null matrix
  • diagonal matrix
  • symmetric matrix
  • unit matrix
  • trace of a matrix

Matrix algebra

🔗
  • sum of matrices
  • product of matrices
  • matrix transpose
  • matrix scalar product
  • matrix Hadamart product
  • matrix concatenation
  • matrix-vector product
  • matrix power
  • matrix exponential

Determinant

🔗
  • 2x2
  • 3x3
  • nxn

Inverse

🔗
  • general expression

Left and Right Inverse (topic for advanced-linear-algebra?)

🔗
  • what if the matrix is not square? (topic for advanced-linear-algebra?)
  • Moore-Penrose pseudo-inverse

Eigenvalues and Eigenvectors

🔗
  • for square matrices
  • for rectangular matrices (topic for advanced-linear-algebra?)
  • singular value decomposition SVD (topic for advanced-linear-algebra?)

Matrix as representation of linear (vector) spaces

🔗
  • linear system to matrix representation
  • linearly dependent and independent spaces

Fundamental spaces

🔗
  • Null space
  • Range/image

Preferred spaces (matrix diagonalization)

🔗
  • show how to diagonalize matrices and why it is relevant (it will come in handy for state space representation chapter chapter)

Examples

🔗

Theoretical Examples

🔗

Calculate a (square) Matrix Inverse

🔗

Find eigenvalues and eigenvectors

🔗

Find range and null spaces of a matrix

🔗

Implementation Examples

🔗

Inverting a well conditioned matrix

🔗

Inverting a ill conditioned matrix

🔗

Pointers to Exercises

🔗

Here we just add references to the suggested exercises, defined in the appropriate exercise chapters.

Conclusions

🔗

In this section we have defined the fundamental concept of linearity and introduced the mathematical tools pertaining to it, in particular vectors and matrices. Moreover, we have introduced their properties and interpretations as linear spaces.

We have found that matrices are a very convenient way to represent linear spaces, and that the properties of the matrices such as eigenvalues and eigenvectors have important implications in charachterizing these spaces.

These tools are useful because they are at the foundation of modeling of natural phenomena. Modeling will be invaluable in understanding the behaviour of systems, and a powerful tool to predict future behaviours of the system, and control them when needed.

We have learned that …

Next Steps

🔗
  • linearization of non linear equations
  • state space representations
  • basic kinematics
  • basic dynamics

Jacopo Maintainer: Jacopo Point of Contact: Jacopo

Because of mathjax bug

Probability basics

🔗

Liam?

Because of mathjax bug

Dynamics

🔗

Jacopo

this is a repetition of Chapter 50.

Because of mathjax bug

Coordinate systems

🔗

Falcon

Provide a basic description of coordinate systems. The description of general coordinate systems should be brief, with the majority of the text focusing on Cartesian coordinate systems (2D and 3D), polar coordinate systems, and spherical coordinate systems.

Because of mathjax bug

Reference frames

🔗

TBD

Required Reading: The following assumes a working familiarity with 2D and 3D Cartesian coordinate systems. If you are not familiar with Cartesian coordinate systems, please read the chapter on coordinate systems.

Provide a basic description of reference frames. This section is dependent upon the coordinate systems chapter and could be moved there.

Because of mathjax bug

Transformations

🔗

TBD

Required Reading: The following assumes a working familiarity with 2D and 3D Cartesian reference frames. If you are not familiar with Cartesian reference frames, please read the chapter on reference frames.

Provide a basic description of transformations (rotations and translations) in 2D and 3D Cartesian reference frames.

Because of mathjax bug

Autonomy overview

🔗

Liam

In this chapter we will introduce some basic concepts ubiquitous in autonomous vehicle navigation.

Basic Building Blocks of Autonomy

🔗

The minimal basic backbone processing pipeline for autonomous vehicle navigation is shown in Figure 55.

The basic building blocks of any autonomous vehicle

For an autonomous vehicle to function, it must achieve some level of performance for all of these components. The level of performance required depends on the task and the required performance .In the remainder of this section, we will discuss some of the most basic options. In the next section we will briefly introduce some of the more advanced options that are used in state-of-the-art autonomous vehicles.

Sensors

🔗

Sensor A sensor is a device that or mechanism that is capable of generating a measurement of some external phyiscal quantity

In general, sensors have two major types. Passive sensors generate measurements without affecting the environment that they are measuring. Examples include inertial sensors, odometers, GPS receivers, and cameras. Active sensors emit some form of energy into the environment in order to make a measurement. Examples of this type of sensor include Light Detection And Ranging (LiDAR), Radio Detection And Ranging (RaDAR), and Sound Navigation and Ranging (SoNAR). All of these sensors emit energy (from different spectra) into the environment and then detect some property of the energy that is reflected from the environment (e.g., the time of flight or the phase shift of the signal)

Raw Data Processing

🔗

The raw data that is input from a sensor needs to be processed in order to become useful and even understandandable to a human.

First, calibration is usually required to convert convert units, for example from a voltage to a physical quantity. As a simple example consider a thermometer, which measures temperature via an expanding liquid (usually mercury). The calibration is the known mapping from amount of expansion of liquid to temperature. In this case it is a linear mapping and is used to put the markings on the thermometer that make it useful as a sensor.

We will distiguish between two fundamentally types of calibrations.

Intrinsic Calibration{def:intrinsic-calibration} An intrinsic calibration is required to determine sensor-specific paramaters that are internal to a specific sensor.

Extrinsic Calibration{def:extrinsic-calibration} An extrinsic calibration is required to determine the external configuration of the sensor with respect to some reference frame.

For more information about reference frames check out Chapter 42

Calibration is very important consideration in robotics. In the field, the most advanced algorithms will fail if sensors are not properly calibrated.

Once we have properly calibrated data in some meaningful units, we often do some preprocessing to reduce the overall size of the data. This is true particularly for sensors that generate a lot of data, like cameras. Rather than deal with every pixel value generated by the camera, we will process an image to generate feature-points of interest. In ``classical” computer vision many different feature descriptors have been proposed (Harris, BRIEF, BRISK, SURF, SIFT, etc), and more recently Convolutional Neural Networks (CNNs) are being used to learn these features.

The important property of these features is that they should be as easily to associate as possible across frames. In order to achieve this, the feature descriptors should be invariant to nuissance parameters.

add a picture with basic feature detections

State Estimation

🔗

Now that we have used our sensors to generate a set of meaningful measurements, we need to combine these measurements together to produce an estimate of the underlying hidden state of the robot and possibly to environment.

Planning and Control

🔗

State->control

Actuation

🔗

Control applied to vehicle

Infrasctructure and Prior Information

🔗

Advanced Building Blocks of Autonomy

🔗
Because of mathjax bug

Autonomy architectures

🔗

Andrea

Contracts

🔗
API: Types, messages
Latency, frequency
computation
semantics
reliability / probability
Because of mathjax bug

Representations

🔗

Matt

Required Reading: The following assumes working knowledge of 2D and 3D Cartesian coordinate systems, reference frames, and coordinate transformations. If you are not familiar with these topics, please see the chapters on coordinate systems, reference frames, and coordinate transformations.

Discuss:

  • Introduction to the notion of state as a sufficient statistic that represents the agent (robot) and environment.
  • Describe qualities: sufficient statistic; compact (i.e., not conveying unnecessary information); and readily interpretable.
  • Define notion of static and dynamic states.
  • Provide examples of robot and environment states.

The planning and control capabilities necessary for autonomy rely upon shared representations of the agent (i.e., the robot) and the environment in which it operates. Referred to as the state, this representation consists of a compilation of all knowledge about the robot and its environment that is sufficient both to perform a particular task as well as to predict the future. Ignoring prior information, this knowledge is often extracted from the robot’s multimodal sensor streams (e.g., wheel encoders and cameras). Consequently, a natural choice is to formulate the state as the collection of all of the measurements that the robot acquires over time. Indeed, the use of low-level sensor measurements as the representation of the state has a long history in robotics and artificial intelligence (cite) and has received renewed attention of-late (cite).

However, while measurement history is a sufficient representation of the robot and its operating environment, several limitations limit its utility for planning and control. First, measurement history is redundant within individual and across successive observations. Second, the observations contain a large amount of unnecessary information (e.g., pixel intensities associated with clouds are not useful for self-driving vehicles). Third, measurement history is very inefficient: its size grows linearly with time (i.e., as the robot acquires new measurements), and it it may be computationally intractable to access and process such a large amount of data. This motivates the desire for a minimal representation that expresses knowledge that is both necessary and sufficient for the robot to perform a given task. More concretely, we will consider parameterized (symbolic) formulations of the state and will prefer representations that involve as small a number of parameters as possible, subject to the constraints imposed by the task.

Preliminaries

🔗

I’ve created (currently empty) chapters for each of the following

Robot Representations

🔗

Define the notion of:

  • pose for mobile robots;
  • configuration for manipulators
  • robot and joint velocities

Discuss specific robot state representation for Duckietown.

Environment Representations

🔗

Discuss:

  • Difference between topological and metric environment representations;
  • Details of topological representation;
  • Common metric representations, notably feature-based maps and gridmaps;

Duckietown Environment Representation

🔗

Discuss specific environment representation for Duckietown.

Because of mathjax bug

Software architectures and middlewares

🔗

Andrea

Because of mathjax bug

Modern signal processing

🔗

Andrea

Because of mathjax bug

Basic Kinematics

🔗

Jacopo

Because of mathjax bug

Basic Dynamics

🔗

Jacopo

Because of mathjax bug

Odometry Calibration

🔗

Jacopo

Because of mathjax bug

Computer vision basics

🔗

Matt

Because of mathjax bug

Illumination invariance

🔗

Matt

Because of mathjax bug

Line Detection

🔗

Matt

Because of mathjax bug

Feature extraction

🔗

Matt

Because of mathjax bug

Place recognition

🔗

Matt

Because of mathjax bug

Filtering 1

🔗

Liam

Because of mathjax bug

Filtering 2

🔗

Liam

Because of mathjax bug

Mission planning

🔗

ETH

Because of mathjax bug

Planning in discrete domains

🔗

ETH

Because of mathjax bug

Motion planning

🔗

ETH

Because of mathjax bug

RRT

🔗

ETH

Because of mathjax bug

Feedback control

🔗

Jacopo

Because of mathjax bug

PID Control

🔗

Jacopo

Because of mathjax bug

MPC Control

🔗

Jacopo

Because of mathjax bug

Object detection

🔗

Nick and David

Because of mathjax bug

Object classification

🔗

Nick and David

Because of mathjax bug

Object tracking

🔗

Nick and David

Because of mathjax bug

Reacting to obstacles

🔗

Jacopo

Because of mathjax bug

Semantic segmentation

🔗

Nick and David

Because of mathjax bug

Text recognition

🔗

Nick

Because of mathjax bug

SLAM - Problem formulation

🔗

Liam

Because of mathjax bug

SLAM - Broad categories

🔗

Liam

Because of mathjax bug

VINS

🔗

Liam

Because of mathjax bug

Advanced place recognition

🔗

Liam

Because of mathjax bug

Fleet level planning (placeholder)

🔗

ETH

Because of mathjax bug

Fleet level planning (placeholder)

🔗

ETH

Because of mathjax bug

Bibliography

🔗
Jacopo Tani, Liam Paull, Maria Zuber, Daniela Rus, Jonathan How, John Leonard, and Andrea Censi. Duckietown: an innovative way to teach autonomy. In EduRobotics 2016. Athens, Greece, December 2016. pdf supp. materialbibtex Liam Paull, Jacopo Tani, Heejin Ahn, Javier Alonso-Mora, Luca Carlone, Michal Cap, Yu Fan Chen, Changhyun Choi, Jeff Dusek, Daniel Hoehener, Shih-Yuan Liu, Michael Novitzky, Igor Franzoni Okuyama, Jason Pazis, Guy Rosman, Valerio Varricchio, Hsueh-Cheng Wang, Dmitry Yershov, Hang Zhao, Michael Benjamin, Christopher Carr, Maria Zuber, Sertac Karaman, Emilio Frazzoli, Domitilla Del Vecchio, Daniela Rus, Jonathan How, John Leonard, and Andrea Censi. Duckietown: an open, inexpensive and flexible platform for autonomy education and research. In IEEE International Conference on Robotics and Automation (ICRA). Singapore, May 2017. pdf supp. materialbibtex Bruno Siciliano and Oussama Khatib. Springer Handbook of Robotics. Springer-Verlag New York, Inc., Secaucus, NJ, USA, 2007.    Tosini, G., Ferguson, I., Tsubota, K. Effects of blue light on the circadian system and eye physiology. Molecular Vision, 22, 61–72, 2016 (online). Albert Einstein. Zur Elektrodynamik bewegter Körper. (German) On the electrodynamics of moving bodies. Annalen der Physik, 322(10):891–921, 1905.    DOI  Ivan Savov. Linear algebra explained in four pages. https://minireference.com/static/tutorials/linear_algebra_in_4_pages.pdf, 2017. Online; accessed 23 August 2017.    Kaare Brandt Petersen and Michael Syskind Pedersen. The matrix cookbook.    .pdf 
Because of mathjax bug

Exercises

🔗

These are the exercises.

Because of mathjax bug

ROS Exercises

🔗

Progression of ROS skills:

Parameters

🔗
  • Reading parameters
  • Dynamic modification of parameters

Running from a log

🔗
  • Running from a log

Unit tests

🔗
  • Unit tests
  • Integration with ROS tests

Analytics

🔗
  • Measure the latency and frequency of the node

  • Measure the latency of another node

Visualization

🔗
  • Making a plot displayed using topic

  • Using ROS parameters

Because of mathjax bug

Line detection

🔗
Because of mathjax bug

Data processing

🔗
Because of mathjax bug

Git and conventions

🔗
Because of mathjax bug

Software reference

🔗

This part describes things that you should know about UNIX/Linux environments.

Documentation writers: please make sure that every command used has a section in these chapters.

Because of mathjax bug

Ubuntu packaging with APT

🔗

apt install

🔗

to write

apt update

🔗

to write

apt dist-upgrade

🔗

hold back packages

apt-key

🔗

to write

apt-mark

🔗

to write

add-apt-repository

🔗

to write

wajig

🔗

to write

dpigs

🔗

to write

Because of mathjax bug

GNU/Linux general notions

🔗

Andrea

Background reading

🔗
  • UNIX
  • Linux
  • free software; open source software.

Every day Linux

🔗

cd

🔗

to write

sudo

🔗

to write

ls

🔗

to write

cp

🔗

to write

mkdir

🔗

to write

touch

🔗

to write

reboot

🔗

to write

shutdown

🔗

to write

rm

🔗

to write

Users

🔗

passwd

🔗

to write

UNIX tools

🔗

cat

🔗

to write

tee

🔗

to write

truncate

🔗

to write

Linux disks and files

🔗

fdisk

🔗

to write

mount

🔗

to write

umount

🔗

to write

losetup

🔗

to write

gparted

🔗

to write

dd

🔗

to write

sync

🔗

to write

df

🔗

to write

Other administration commands

🔗

visudo

🔗

to write

update-alternatives

🔗

to write

udevadm

🔗

to write

systemctl

🔗

to write

Make

🔗

make

🔗

to write

Raspberry-PI commands

🔗

raspi-config

🔗

to write

vcgencmd

🔗

to write

raspistill

🔗

to write

jstest

🔗

to write

swapon

🔗

to write

mkswap

🔗

to write

Users and permissions

🔗

chmod

🔗

to write

groups

🔗

to write

adduser

🔗

to write

useradd

🔗

to write

Downloading

🔗

curl

🔗

to write

wget

🔗

to write

sha256sum

🔗

to write

xz

🔗

to write

Shells and environments

🔗

source

🔗

to write

which

🔗

to write

export

🔗

to write

Other misc commands

🔗

pgrep

🔗

to write

npm

🔗

to write

nodejs

🔗

to write

ntpdate

🔗

to write

chsh

🔗

to write

echo

🔗

to write

sh

🔗

to write

fc-cache

🔗

to write

Because of mathjax bug

Linux resources usage

🔗

Measuring CPU usage using htop

🔗

You can use htop to monitor CPU usage.

$ sudo apt install htop

to write

Measuring I/O usage using iotop

🔗

Install using:

$ sudo apt install iotop

to write

How fast is the SD card?

🔗
Because of mathjax bug

SD Cards tools

🔗

Testing SD Card and disk speed

🔗

Test SD Card (or any disk) speed using the following commands, which write to a file called filename.

$ dd if=/dev/zero of=filename bs=500K count=1024
$ sync
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
$ dd if=filename of=/dev/null bs=500K count=1024
$ rm filename

Note the sync and the echo command are very important.

Example results:

524288000 bytes (524 MB, 500 MiB) copied, 30.2087 s, 17.4 MB/s
524288000 bytes (524 MB, 500 MiB) copied, 23.3568 s, 22.4 MB/s

That is write 17.4 MB/s, read 22 MB/s.

How to burn an image to an SD card

🔗

Requires:

  • A blank SD card.
  • An image file to burn.
  • An Ubuntu computer with an SD reader.

Results:

  • A burned image.

Finding your device name for the SD card

🔗

First, find out what is the device name for the SD card.

Insert the SD Card in the slot.

Run the command:

$ sudo fdisk -l

Find your device name, by looking at the sizes.

For example, the output might contain:

Disk /dev/mmcblk0: 14.9 GiB, 15931539456 bytes, 31116288 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

In this case, the device is /dev/mmcblk0. That will be the device in the next commands.

You may see /dev/mmcblk0pX or a couple of similar entries for each partition on the card, where X is the partition number. If you don’t see anything like that, take out the SD card and run the command again and see what disappeared.

Unmount partitions

🔗

Before proceeding, unmount all partitions.

Run df -h. If there are partitions like /dev/mmcblk0pn, then unmount each of them. For example:

laptop $ sudo umount /dev/mmcblk0p1
laptop $ sudo umount /dev/mmcblk0p2

Burn the image

🔗

Now that you know that the device is device, you can burn the image to disk.

Let the image file be image file.

Burn the image using the command dd:

laptop $ sudo dd of=device if=image file status=progress bs=4M

Use the name of the device, without partitions. i.e., /dev/mmcblk0, not /dev/mmcblk0pX.

How to shrink an image

🔗

Requires:

  • An image file to burn.
  • An Ubuntu computer.

Results:

  • A shrunk image.

Majority of content taken from here

We are going to use the tool gparted so make sure it’s installed

laptop $ sudo apt install gparted

Let the image file be image file. Run the command:

laptop $ sudo fdisk -l image file

It should give you something like:

Device                       Boot  Start      End  Sectors  Size Id Type
duckiebot-RPI3-LP-aug15.img1        2048   131071   129024   63M  c W95 FAT32 (LBA)
duckiebot-RPI3-LP-aug15.img2      131072 21219327 21088256 10.1G 83 Linux

Take note of the start of the Linux partition (in our case 131072), let’s call it start. Now we are going to mount the Linux partition from the image:

laptop $ sudo losetup /dev/loop0 imagename.img -o $((start*512))

and then run gparted:

laptop $ sudo gparted /dev/loop0

In gparted click on the partition and click “Resize” under the “Partition” menu. Resize drag the arrow or enter a size that is equal to the minimum size plus 20MB

This didn’t work well for me - I had to add much more than 20MB for it to work.

Click the “Apply” check mark. Before closing the final screen click through the arrows in the dialogue box to find a line such a “resize2fs -p /dev/loop0 1410048K”. Take note of the new size of your partition. Let’s call it new size.

Now remove the loopback on the second partition and setup a loopback on the whole image and run fdisk:

laptop $ sudo losetup -d /dev/loop0
laptop $ sudo losetup /dev/loop0 image file
laptop $ sudo fdisk /dev/loop0

Command (m for help): enter d
Partition number (1,2, default 2): enter 2
Command (m for help): enter n
Partition type
p   primary (1 primary, 0 extended, 3 free)
e   extended (container for logical partitions)
Select (default p): enter p
Partition number (2-4, default 2): enter 2
First sector (131072-62521343, default 131072): start
Last sector, +sectors or +size{K,M,G,T,P} (131072-62521343, default 62521343): +new sizeK

on the last line include the + and the K as part of the size.

Created a new partition 2 of type 'Linux' and of size 10.1 GiB.

Command (m for help): enter w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Invalid argument

The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).

Disregard the final error.

You partition has now been resized and the partition table has been updated. Now we will remove the loopback and then truncate the end of the image file:

laptop $ fdisk -l /dev/loop0

Device       Boot  Start      End  Sectors  Size Id Type
/dev/loop0p1        2048   131071   129024   63M  c W95 FAT32 (LBA)
/dev/loop0p2      131072 21219327 21088256 10.1G 83 Linux

Note down the end of the second partition (in this case 21219327). Call this end.

laptop $ sudo losetup -d /dev/loop0
laptop $ sudo truncate -s $(((end+1)*512)) image file

You now have a shrunken image file. A further idea is to compress it:

laptop $ xz image file
Because of mathjax bug

Networking tools

🔗

Andrea

Preliminary reading:

  • Basics of networking, including

    • what are IP addresses
    • what are subnets
    • how DNS works
    • how .local names work

(ref to find).

to write

Make sure that you know:

hostname

🔗

to write

Visualizing information about the network

🔗

ping: are you there?

🔗

to write

ifconfig

🔗

to write

$ ifconfig
Because of mathjax bug

Accessing computers using SSH

🔗

Andrea

Background reading

🔗

to write

  • Encryption
  • Public key authentication

Installation of SSH

🔗

This installs the client:

$ sudo apt install ssh

This installs the server:

to write

This enables the server:

to write

Local configuration

🔗

The SSH configuration as a client is in the file

~/.ssh/config

Create the directory with the right permissions:

$ mkdir ~/.ssh
$ chmod 0700 ~/.ssh

Then add the following lines:

HostKeyAlgorithms ssh-rsa

The reason is that Paramiko, used by roslaunch, does not support the ECSDA keys.

How to login with SSH and a password

🔗

To log in to a remote computer remote with user remote-user, use:

$ ssh remote-user@remote

Troubleshooting

🔗

Symptom: “Offending key error”.

If you get something like this:

Warning: the ECDSA host key for ... differs from the key for the IP address '... '

Offending key for IP in /home/user/.ssh/known_hosts:line

then remove line line in ~/.ssh/known_hosts.

Creating an SSH keypair

🔗

This is a step that you will repeat twice: once on the Duckiebot, and once on your laptop.

The program will prompt you for the filename on which to save the file.

Use the convention

/home/username/.ssh/username@host name
/home/username/.ssh/username@host name.pub

where:

  • username is the current user name that you are using (ubuntu or your chosen one);
  • host name is the name of the host (the Duckiebot or laptop);

An SSH key can be generated with the command:

$ ssh-keygen -h

The session output will look something like this:

Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):

At this point, tell it to choose this file:

/home/username/.ssh/username@host name

Then:

Enter passphrase (empty for no passphrase):

Press enter; you want an empty passphrase.

Enter same passphrase again:

Press enter.

Your identification has been saved in /home/username/.ssh/username@host name
Your public key has been saved in /home/username/.ssh/username@host name.pub
The key fingerprint is:
XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX username@host name
The key's randomart image is:
+--[ RSA 2048]----+
|            .    |
|       o   o  .  |
|      o = o  . o |
|       B . .  * o|
|        S o    O |
|         o o  . E|
|          o o  o |
|           o  +  |
|            .. . |
+-----------------+

Note that the program created two files.

The file that contains the private key is

/home/username/.ssh/username@host name

The file that contains the public key has extension .pub:

/home/username/.ssh/username@host name.pub

Next, tell SSH that you want to use this key.

Make sure that the file ~/.ssh/config exists:

$ touch ~/.ssh/config

Add a line containing

IdentityFile PRIVATE_KEY_FILE

(using the filename for the private key).

Check that the config file is correct:

$ cat ~/.ssh/config
...
IdentityFile PRIVATE_KEY_FILE
...

How to login without a password

🔗

Assumptions:

  • You have two computers, called “local” and “remote”, with users “local-user” and “remote-user”.
  • The two computers are on the same network.
  • You have created a keypair for local-user on local.

This procedure is described in Section 100.5.

Results:

  • From the local computer, local-user will be able to log in to remote computer without a password.

First, connect the two computers to the same network, and make sure that you can ping remote from local:

local $ ping remote.local

Do not continue if you cannot do this successfully.

If you have created a keypair for local-user, you will have a public key in this file on the local computer:

/home/local-user/.ssh/local-user@local.pub

This file is in the form:

ssh-rsa long list of letters and numbers local-user@local

You will have to copy the contents of this file on the remote computer, to tell it that this key is authorized.

On the remote computer, edit or create the file:

/home/remote-user/.ssh/authorized_keys

and add the entire line as above containing the public key.

Now, from the local computer, try to log in into the remote one:

local $ ssh remote-user@remote

This should succeed, and you should not be asked for a password.

Fixing SSH Permissions

🔗

Sometimes, SSH does not work because you have the wrong permissions on some files.

In doubt, these lines fix the permissions for your .ssh directory.

$ chmod 0700 ~/.ssh
$ chmod 0700 ~/.ssh/*

ssh-keygen

🔗

to write

Because of mathjax bug

Wireless networking in Linux

🔗

iwconfig

🔗

to write

iwlist

🔗

Getting a list of WiFi networks

🔗

What wireless networks do I have around?

$ sudo iwlist interface scan | grep SSID

Do I have 5 GHz?

🔗

Does the interface support 5 GHz channels?

$ sudo iwlist interface freq

Example output:

wlx74da38c9caa0  20 channels in total; available frequencies :
  Channel 01 : 2.412 GHz
  Channel 02 : 2.417 GHz
  Channel 03 : 2.422 GHz
  Channel 04 : 2.427 GHz
  Channel 05 : 2.432 GHz
  Channel 06 : 2.437 GHz
  Channel 07 : 2.442 GHz
  Channel 08 : 2.447 GHz
  Channel 09 : 2.452 GHz
  Channel 10 : 2.457 GHz
  Channel 11 : 2.462 GHz
  Channel 36 : 5.18 GHz
  Channel 40 : 5.2 GHz
  Channel 44 : 5.22 GHz
  Channel 48 : 5.24 GHz
  Channel 149 : 5.745 GHz
  Channel 153 : 5.765 GHz
  Channel 157 : 5.785 GHz
  Channel 161 : 5.805 GHz
  Channel 165 : 5.825 GHz
  Current Frequency:2.437 GHz (Channel 6)

Note that in this example only some 5Ghz channels are supported (36, 40, 44, 48, 149, 153, 157, 161, 165); for example, channel 38, 42, 50 are not supported. This means that you need to set up the router not to use those channels.

Because of mathjax bug

Moving files between computers

🔗

SCP

🔗

to write

Download a file with SCP

🔗

to write

RSync

🔗

to write

Because of mathjax bug

VIM

🔗

Andrea

To do quick changes to files, especially when logged remotely, we suggest you use the VI editor, or more precisely, VIM (“VI iMproved”).

External documentation

🔗

Installation

🔗

Install like this:

$ sudo apt install vim

vi

🔗

to write

Suggested configuration

🔗

Suggested ~/.vimrc:

syntax on
set number
filetype plugin indent on
highlight Comment ctermfg=Gray
autocmd FileType python set complete isk+=.,(

Visual mode

🔗

to write

Indenting using VIM

🔗

Use the > command to indent.

To indent 5 lines, use 5 > >.

To mark a block of lines and indent it, use V.

For example, use VJJ> to indent 3 lines.

Use < to dedent.

Because of mathjax bug

Atom

🔗

to write

Because of mathjax bug

Eclipse

🔗

to write

Installing LiClipse

🔗

to write

Because of mathjax bug

Byobu

🔗

Andrea

You need to learn to use Byobu. It will save you much time later.

(Alternatives such as GNU Screen are fine as well.)

Advantages of using Byobu

🔗

To write

Installation

🔗

On Ubuntu, install using:

$ sudo apt install byobu

Documentation

🔗

See the screencast on the website http://byobu.co/.

Quick command reference

🔗

You can change the escape sequence from Ctrl-A to something else by using the configuration tool that appears when you type F9.

Commands to use windows:

Windows
Using function keys Using escape sequences
Create new window F2 Ctrl-A then C
Previous window F3
Next window F4
Switch to window Ctrl-A then a number
Close window F6
Rename window Ctrl-A then ,

Commands to use panes (windows split in two or more):

Commands for panes
Using function keys Using escape sequences
Split horizontally Shift-F2 Ctrl-A then |
Split vertically Ctrl-F2 Ctrl-A then %
Switch focus among panes Ctrl-↑↓←→ Ctrl-A then one of ↑↓←→
Break pane Ctrl-A then !

Other commands:

Other
Using function keys Using escape sequences
Help Ctrl-A then ?
Detach Ctrl-A then D

Commands on OS X

🔗

Scroll up and down using fnoption and fnoption.

Highlight using alt

Because of mathjax bug

Source code control with Git

🔗

Andrea

Background reading

🔗

to write

  • Git
  • GitFlow

Installation

🔗

The basic Git program is installed using

$ sudo apt install git

Additional utilities for git are installed using:

$ sudo apt install git-extras

This include the git-ignore utility.

Setting up global configurations for Git

🔗

This should be done twice, once on the laptop, and later, on the robot.

These options tell Git who you are:

$ git config --global user.email "email"
$ git config --global user.name  "full name"

Also do this, and it doesn’t matter if you don’t know what it is:

$ git config --global push.default simple

Git tips

🔗

Shallow clone

🔗

You can clone without history with the command:

$ git clone --depth 1 repository URL

Git troubleshooting

🔗

Problem 1: https instead of ssh:

🔗

The symptom is:

$ git push
Username for 'https://github.com':

Diagnosis: the remote is not correct.

If you do git remote you get entries with https::

$ git remote -v
origin  https://github.com/duckietown/Software.git (fetch)
origin  https://github.com/duckietown/Software.git (push)

Expectation:

$ git remote -v
origin  git@github.com:duckietown/Software.git (fetch)
origin  git@github.com:duckietown/Software.git (push)

Solution:

$ git remote remove origin
$ git remote add origin git@github.com:duckietown/Software.git

Problem 1: git push complains about upstream

🔗

The symptom is:

fatal: The current branch branch name has no upstream branch.

Solution:

$ git push --set-upstream origin branch name

git

🔗

to write

Because of mathjax bug

Git LFS

🔗

This describes Git LFS.

Generic installation instructions

🔗

See instructions at:

https://git-lfs.github.com/

Ubuntu 16 installation (laptop)

🔗

Following these instructions, run the following:

$ sudo add-apt-repository ppa:git-core/ppa
$ curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
$ sudo apt update
$ sudo apt install git-lfs

Ubuntu 16 Mate installation (Raspberry Pi 3)

🔗

unresolved issues.

The instructions above do not work.

Following this, the error that appears is that golang on the Pi is 1.6 instead it should be 1.7.

Troubleshooting

🔗

The binary files are not downloaded. In their place, there are short “pointer” files.

If you have installed LFS after pulling the repository and you see only the pointer files, do:

$ git lfs pull --all
Because of mathjax bug

Setup Github access

🔗

Andrea

This chapter describes how to create a Github account and setup SSH on the robot and on the laptop.

Create a Github account

🔗

Our example account is the following:

Github name: greta-p
E-mail: greta-p@duckietown.com

Create a Github account (Figure 56).

Go to your inbox and verify the email.

Become a member of the Duckietown organization

🔗

Give the administrators your account name. They will invite you.

Accept the invitation to join the organization that you will find in your email.

Add a public key to Github

🔗

You will do this procedure twice: once for the public key created on the laptop, and later with the public key created on the robot.

Requires:

  • A public/private keypair already created and configured.

This procedure is explained in Section 100.5.

Result:

  • You can access Github using the key provided.

Go to settings (Figure 57).

Add the public key that you created:

To check that all of this works, use the command

$ ssh -T git@github.com

The command tries to connect to Github using the private keys that you specified. This is the expected output:

Warning: Permanently added the RSA host key for IP address 'ip address' to the list of known hosts.
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

If you don’t see the greeting, stop.

Repeat what you just did for the Duckiebot on the laptop as well, making sure to change the name of the file containing the private key.

Because of mathjax bug

ROS installation and reference

🔗

Liam

Install ROS

🔗

This part installs ROS. You will run this twice, once on the laptop, once on the robot.

The first commands are copied from this page.

Tell Ubuntu where to find ROS:

$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

Tell Ubuntu that you trust the ROS people (they are nice folks):

$ sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116

Fetch the ROS repo:

$ sudo apt update

Now install the mega-package ros-kinetic-desktop-full.

$ sudo apt install ros-kinetic-desktop-full

There’s more to install:

$ sudo apt install ros-kinetic-{tf-conversions,cv-bridge,image-transport,camera-info-manager,theora-image-transport,joy,image-proc,compressed-image-transport,phidgets-drivers,imu-complementary-filter,imu-filter-madgwick}

Do not install packages by the name of ros-X, only those by the name of ros-kinetic-X. The packages ros-X are from another version of ROS.

: not done in aug20 image:

Initialize ROS:

$ sudo rosdep init
$ rosdep update

rqt_console

🔗

to write

roslaunch

🔗

to write

rviz

🔗

to write

rostopic

🔗

to write

rostopic hz

🔗

to write

rostopic echo

🔗

to write

catkin_make

🔗

to write

rosrun

🔗

to write

rostest

🔗

to write

rospack

🔗

to write

rosparam

🔗

to write

rosdep

🔗

to write

roswtf

🔗

to write

rosbag

🔗
$ rosbag reindex bag file

roscore

🔗

to write

Troubleshooting ROS

🔗

computer is not in your SSH known_hosts file

See this thread. Remove the known_hosts file and make sure you have followed the instructions in Section 100.3.

Other materials about ROS.

🔗
Because of mathjax bug

Software development guide

🔗

This part is about how to develop software for the Duckiebot.

Because of mathjax bug

Python

🔗

Background reading

🔗
  • Python
  • Python tutorial

Python virtual environments

🔗

Install using:

$ sudo apt install virtualenv

Useful libraries

🔗
matplotlib
seaborne
numpy
panda
scipy
opencv
...

Context managers

🔗

to write

Because of mathjax bug

Duckietown code conventions

🔗

Python

🔗

Tabs

🔗

Never use tabs in Python file.

The tab characters are evil in Python code. Please be very careful in changing them.

Do not use a tool to do it (e.g. “Convert tabs to spaces”); it will get it wrong.

checked by what-the-duck.

Spaces

🔗

Indentation is 4 spaces.

Line lengths

🔗

Lines should be below 85 characters.

what-the-duck report those above 100 characters.

This is just a symptom of a bigger problem.

The problem here is that you do not do how to program well, therefore you create programs with longer lines.

Do not go and try to shorten the lines; the line length is just the symptom. Rather, ask somebody to take a look at the code and tell you how to make it better.

Spaces

🔗

Indentation is 4 spaces.

The encoding line

🔗

All files must have an encoding declared, and this encoding must be utf-8:

# -*- coding: utf-8 -*-

Sha-bang lines

🔗

Executable files start with:

#!/usr/bin/env python

Comments

🔗

Comments refer to the next line.

Comments, bad:

from std_msgs.msg import String # This is my long comment

Comments, better:

# This is my long comment
from std_msgs.msg import String

Logging

🔗

For logging, import this logger:

from duckietown_utils import logger

Exceptions

🔗
DTConfigException

raise_wrapped
compact = True

Scripts

🔗
def summary():
    fs = get_all_configuration_files()


if __name__ == '__main__':
    wrap_script_entry_point(summary)

Imports

🔗

Do not do a star import, like the following:

from rostest_example.Quacker import *
Because of mathjax bug

Configuration

🔗

This chapter explains what are the assumptions about the configuration.

While the “Setup” parts are “imperative” (do this, do that); this is the “declarative” part, which explains what are the properties of a correct configuration (but it does not explain how to get there).

he tool what-the-duck (Section 161.2) checks some of these conditions. If you make a change from the existing conditions, make sure that it gets implemented in what-the-duck by filing an issue.

Environment variables

🔗

You need to have set up the variables in Table 18.

Environment variables used by the software
variable reasonable value contains
DUCKIETOWN_ROOT ~/duckietown Software repository
DUCKIEFLEET_ROOT ~/duckiefleet A repository that contains scuderia.yaml and other team-specific configuration.
DUCKIETOWN_DATA ~/duckietown-data Contains data for unit tests (Dropbox folder)
DUCKIETOWN_CONFIG_SEQUENCE defaults:baseline:vehicle:user The configuration sequence for EasyNode

Duckietown root directory DUCKIETOWN_ROOT

🔗

to write

Duckiefleet directory DUCKIEFLEET_ROOT

🔗

For Fall 2017, this is the the repository duckiefleet-fall2017.

For self-guided learners, this is an arbitrary repository to create.

The scuderia file

🔗

In the ${DUCKIEFLEET_ROOT} directory, there needs to exist a file called:

${DUCKIEFLEET_ROOT}/scuderia.yaml

The file must contain YAML entries of the type:

robot-name:
   username: username
   owner_duckietown_id: owner duckietown ID

A minimal example is in Listing 6.

emma:
  username: andrea
  owner_duckietown_id: censi
Minimal scuderia file

Explanations of the fields:

  • robot name: the name of the robot, also equal to the host name.
  • username: the name of the Linux user on the robot, from which to run programs.
  • owner_duckietown_id: the owner’s globally-unique Duckietown ID.

I am still not satisfied. We should have a separate file for every robot, called robot name.vehicle.yaml. In this way, people don’t have to work on the same file. Then scuderia.yaml can be autogenerated from those files.

The machines file

🔗

The machines file is created using:

$ rosrun duckietown create-machines-file

People database

🔗

Andrea

Describe the people database; this is the evolution of the yaml files

The globally-unique Duckietown ID

🔗

This is a globally-unique ID for people in the Duckietown project.

It is equal to the Slack username.

Modes of operation

🔗

There are 3 modes of operation:

  1. MODE-normal: Everything runs on the robot.
  2. MODE-offload: Drivers run on the robot, but heavy computation runs on the laptop.
  3. MODE-bag: The data is provided from a bag file, and computation runs on the laptop.
Operation modes
mode name who is the ROS master where data comes from where heavy computation happen
MODE-normal duckiebot Drivers on Duckiebot duckiebot
MODE-offload duckiebot Drivers on Duckiebot laptop
MODE-bag laptop Bag file laptop
Because of mathjax bug

Node configuration mechanisms

🔗

Where the config files are, how they are used.

Because of mathjax bug

Minimal ROS node - pkg_name

🔗

Andrea

This document outline the process of writing a ROS package and nodes in Python.

To follow along, it is recommend that you duplicate the pkg_name folder and edit the content of the files to make your own package.

The files in the package

🔗

CMakeLists.txt

🔗

We start with CMakeLists.txt.

Every ROS package needs a file CMakeLists.txt, even if you are just using Python code in your package.

documentation about CMakeLists.txt

For a Python package, you only have to pay attention to the following parts.

The line:

project(pkg_name)

defines the name of the project.

The find_package lines:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  duckietown_msgs # Every duckietown packages must use this.
  std_msgs
)

You will have to specify the packages on which your package is dependent.

In Duckietown, most packages depend on duckietown_msgs to make use of the customized messages.

The line:

catkine_python_setup()

tells catkin to setup Python-related stuff for this package.

package.xml

🔗

The file package.xml defines the meta data of the package.

Catkin makes use of it to flush out the dependency tree and figures out the order of compiling.

Pay attention to the following parts.

<name> defines the name of the package. It has to match the project name in CMakeLists.txt.

<description> describes the package concisely.

<maintainer> provides information of the maintainer.

<build_depend> and <run_depend>. The catkin packages this package depends on. This usually match the find_package in CMakeLists.txt.

setup.py

🔗

The file setup.py configures the Python modules in this package.

The part to pay attention to is

setup_args = generate_distutils_setup(
    packages=['pkg_name'],
    package_dir={'': 'include'},
)

The packages parameter is set to a list of strings of the name of the folders inside the include folder.

The convention is to set the folder name the same as the package name. Here it’s the include/pkg_name folder.

You should put ROS-independent and/or reusable module (for other packages) in the include/pkg_name folder.

Python files in this folder (for example, the util.py) will be available to scripts in the catkin workspace (this package and other packages too).

To use these modules from other packages, use:

from pkg_name.util import *

Writing a node: talker.py

🔗

Let’s look at src/talker.py as an example.

ROS nodes are put under the src folder and they have to be made executable to function properly.

You use chmod for this; see Section 93.1.

Header

🔗

Header:

#!/usr/bin/env python
import rospy
# Imports module. Not limited to modules in this package.
from pkg_name.util import HelloGoodbye
# Imports msg
from std_msgs.msg import String

The first line, #!/usr/bin/env python, specifies that the script is written in Python.

Every ROS node in Python must start with this line.

The line import rospy imports the rospy module necessary for all ROS nodes in Python.

The line from pkg_name.util import HelloGoodbye imports the class HelloGoodbye defined in the file pkg_name/util.py.

Note that you can also include modules provided by other packages, if you specify the dependency in CMakeLists.txt and package.xml.

The line from std_msgs.msg import String imports the String message defined in the std_msgs package.

Note that you can use rosmsg show std_msgs/String in a terminal to lookup the definition of String.msg.

Main

🔗

This is the main file:

if __name__ == '__main__':
    # Initialize the node with rospy
    rospy.init_node('talker', anonymous=False)

    # Create the NodeName object
    node = Talker()

    # Setup proper shutdown behavior
    rospy.on_shutdown(node.on_shutdown)

    # Keep it spinning to keep the node alive
    rospy.spin()

The line rospy.init_node('talker', anonymous=False) initializes a node named talker.

Note that this name can be overwritten by a launch file. The launch file can also push this node down namespaces. If the anonymous argument is set to True then a random string of numbers will be append to the name of the node. Usually we don’t use anonymous nodes.

The line node = Talker() creates an instance of the Talker object. More details in the next section.

The line rospy.on_shutdown(node.on_shutdown) ensures that the node.on_shutdown will be called when the node is shutdown.

The line rospy.spin() blocks to keep the script alive. This makes sure the node stays alive and all the publication/subscriptions work correctly.

The Talker class

🔗

We now discuss the Talker class in talker.py.

Constructor

🔗

In the constructor, we have:

self.node_name = rospy.get_name()

saves the name of the node.

This allows to include the name of the node in printouts to make them more informative. For example:

rospy.loginfo("[%s] Initializing." % (self.node_name))

The line:

self.pub_topic_a = rospy.Publisher("~topic_a", String, queue_size=1)

defines a publisher which publishes a String message to the topic ~topic_a. Note that the ~ in the name of topic under the namespace of the node. More specifically, this will actually publishes to talker/topic_a instead of just topic_a. The queue_size is usually set to 1 on all publishers.

The line:

self.sub_topic_b = rospy.Subscriber("~topic_b", String, self.cbTopic)

defines a subscriber which expects a String message and subscribes to ~topic_b. The message will be handled by the self.cbTopic callback function. Note that similar to the publisher, the ~ in the topic name puts the topic under the namespace of the node. In this case the subscriber actually subscribes to the topic talker/topic_b.

It is strongly encouraged that a node always publishers and subscribes to topics under their node_name namespace. In other words, always put a ~ in front of the topic names when you defines a publisher or a subscriber. They can be easily remapped in a launch file. This makes the node more modular and minimizes the possibility of confusion and naming conflicts. See the launch file section for how remapping works.

The line

self.pub_timestep = self.setupParameter("~pub_timestep", 1.0)

Sets the value of self.pub_timestep to the value of the parameter ~pub_timestep. If the parameter doesn’t exist (not set in the launch file), then set it to the default value 1.0. The setupParameter function also writes the final value to the parameter server. This means that you can rosparam list in a terminal to check the actual values of parameters being set.

The line:

self.timer = rospy.Timer(rospy.Duration.from_sec(self.pub_timestep), self.cbTimer)

defines a timer that calls the self.cbTimer function every self.pub_timestep seconds.

Timer callback

🔗

Contents:

def cbTimer(self,event):
    singer = HelloGoodbye()
    # Simulate hearing something
    msg = String()
    msg.data = singer.sing("duckietown")
    self.pub_topic_name.publish(msg)

Everyt ime the timer ticks, a message is generated and published.

Subscriber callback

🔗

Contents:

def cbTopic(self,msg):
    rospy.loginfo("[%s] %s" %(self.node_name,msg.data))

Every time a message is published to ~topic_b, the cbTopic function is called. It simply prints the messae using rospy.loginfo.

Launch File

🔗

You should always write a launch file to launch a node. It also serves as a documentation on the I/O of the node.

Let’s take a look at launch/test.launch.

<launch>
    <node name="talker" pkg="pkg_name" type="talker.py" output="screen">

        <param name="~pub_timestep" value="0.5"/>

        <remap from="~topic_b" to="~topic_a"/>
    </node>
</launch>

For the <node>, the name specify the name of the node, which overwrites rospy.init_node() in the __main__ of talker.py. The pkg and type specify the package and the script of the node, in this case it’s talke.py.

Don’t forget the .py in the end (and remember to make the file executable through chmod).

The output="screen" direct all the rospy.loginfo to the screen, without this you won’t see any printouts (useful when you want to suppress a node that’s too talkative.)

The <param> can be used to set the parameters. Here we set the ~pub_timestep to 0.5. Note that in this case this sets the value of talker/pub_timestep to 0.5.

The <remap> is used to remap the topic names. In this case we are replacing ~topic_b with ~topic_a so that the subscriber of the node actually listens to its own publisher. Replace the line with

<remap from="~topic_b" to="talker/topic_a"/>

will have the same effect. This is redundant in this case but very useful when you want to subscribe to a topic published by another node.

Testing the node

🔗

First of all, you have to catkin_make the package even if it only uses Python. catkin makes sure that the modules in the include folder and the messages are available to the whole workspace. You can do so by

$ cd ${DUCKIETOWN_ROOT}/catkin_ws
$ catkin_make

Ask ROS to re-index the packages so that you can auto-complete most things.

$ rospack profile

Now you can launch the node by the launch file.

$ roslaunch pkg_name test.launch

You should see something like this in the terminal:

... logging to /home/username/.ros/log/d4db7c80-b272-11e5-8800-5c514fb7f0ed/roslaunch-robot name-15961.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is 1GB.

started roslaunch server http://robot name.local:33925/

SUMMARY
========

PARAMETERS
 * /rosdistro: $ROS_DISTRO
 * /rosversion: 1.11.16
 * /talker/pub_timestep: 0.5

NODES
  /
    talker (pkg_name/talker.py)

auto-starting new master
process[master]: started with pid [15973]
ROS_MASTER_URI=http://localhost:11311

setting /run_id to d4db7c80-b272-11e5-8800-5c514fb7f0ed
process[rosout-1]: started with pid [15986]
started core service [/rosout]
process[talker-2]: started with pid [15993]
[INFO] [WallTime: 1451864197.775356] [/talker] Initialzing.
[INFO] [WallTime: 1451864197.780158] [/talker] ~pub_timestep = 0.5
[INFO] [WallTime: 1451864197.780616] [/talker] Initialzed.
[INFO] [WallTime: 1451864198.281477] [/talker] Goodbye, duckietown.
[INFO] [WallTime: 1451864198.781445] [/talker] Hello, duckietown.
[INFO] [WallTime: 1451864199.281871] [/talker] Goodbye, duckietown.
[INFO] [WallTime: 1451864199.781486] [/talker] Hello, duckietown.
[INFO] [WallTime: 1451864200.281545] [/talker] Goodbye, duckietown.
[INFO] [WallTime: 1451864200.781453] [/talker] Goodbye, duckietown.

Open another terminal and run:

$ rostopic list

You should see

/rosout
/rosout_agg
/talker/topic_a

In the same terminal, run:

$ rosparam list

You should see the list of parameters, including /talker/pub_timestep.

You can see the parameters and the values of the talker node with

$ rosparam get /talker

Documentation

🔗

You should document the parameters and the publish/subscribe topic names of each node in your package. The user should not have to look at the source code to figure out how to use the nodes.

Guidelines

🔗
  • Make sure to put all topics (publish or subscribe) and parameters under the namespace of the node with ~. This makes sure that the IO of the node is crystal clear.
  • Always include the name of the node in the printouts.
  • Always provide a launch file that includes all the parameters (using <param>) and topics (using <remap>) with each node.
Because of mathjax bug

ROS package verification

🔗

This chapter describes formally what makes a conforming ROS package in the Duckietown software architecture.

Naming

🔗

☐ For exercises packages, the name of the package must be package_handle.

package.xml

🔗

☐ There is a package.xml file.

Checked by what-the-duck.

Messages

🔗

☐ The messages are called ….

Readme file

🔗

☐ There is a README.md file

Checked by what-the-duck.

Launch files

🔗

☐ there is the first launch file

Test files

🔗

to write

Because of mathjax bug

Creating unit tests with ROS

🔗
Because of mathjax bug

Duckietown system

🔗

This part describes the Duckietown algorithms and system architecture.

We do not go in the software details. The implementation details have been already talked about at length in Part 9.

We do give links to the ROS packages implementing the functionality.

Because of mathjax bug

Teleoperation

🔗

add video here

Implementation

🔗

Drivers:

Operator interface:

Camera

🔗

to write

Actuators

🔗

to write

IMU

🔗

to write

Because of mathjax bug

Parallel autonomy

🔗

to write

Because of mathjax bug

Lane control

🔗

video here

Implementation

🔗

Perception:

Control:

Because of mathjax bug

Indefinite navigation

🔗

add video here

Implementation

🔗

The packages involved in this functionality are:

we don’t discuss the details of the packages here; we just give pointers to them.

Because of mathjax bug

Planning

🔗

add video here

Implementation

🔗

The packages involved in this functionality are:

we don’t discuss the details of the packages here; we just give pointers to them.

Because of mathjax bug

Coordination

🔗

add video here

Implementation

🔗
Because of mathjax bug

Duckietown ROS Guidelines

🔗

Node and Topics

🔗

In the source code, a node must only publish/subscribe to private topics.

In rospy, this means that the topic argument of rospy.Publisher and rospy.Subscriber should always have a leading ~. ex: ~wheels_cmd, ~mode.

In roscpp, this means that the node handle should always be initialized as a private node handle by supplying with a "~" agrument at initialization. Note that the leading “~” must then be obmitted in the topic names of. ex:

ros::NodeHandle nh_("~");
sub_lineseglist_ = nh_.subscribe("lineseglist_in", 1, &GroundProjection::lineseglist_cb, this);
pub_lineseglist_ = nh_.advertise<duckietown_msgs::SegmentList> ("lineseglist_out", 1);

Parameters

🔗

All the parameters of a node must be private parameters to that node.

All the nodes must write the value of the parameters being used to the parameter server at initialization. This ensures transparence of the parameters. Note that the get_param(name,default_value) does not write the default value to the parameter server automatically.

The default parameter of pkg_name/node_name should be put in ~/duckietown/catkin_ws/src/duckietown/config/baseline/pkg_name/node_name/dafault.yaml. The elemental launch file of this node should load the parameter using <rosparam>.

Launch file

🔗

Each node must have a launch file with the same name in the launch folder of the package. ex: joy_mapper.py must have a joy_mapper.launch. These are referred to as the elemental launch files.

Each elemental launch file must only launch one node.

The elemental launch file should put the node under the correct namespace through the veh arg, load the correct configuration and parameter file throught config and param_file_name args respectively. veh must not have a default value. This is to ensure the user to always provide the veh arg. config must be default to baseline and param_file_name must be default to default.

When a node can be run on the vehicle or on a laptop, the elemental launch file should provide a local arg. When set to true, the node must be launch on the launching machine, when set to false, the node must be launch on a vehicle throught the mahcine attribute.

A node should always be launched by calling its corresponding launch file instead of using rosrun. This ensures that the node is put under the correct namespace and all the necessary parameters are provided.

Do not use <remapp> in the elemental launch files.

Do not use <param> in the elemental launch files.

Because of mathjax bug

Fall 2017

🔗

This is the first time that a class is taught jointly across 3 continents!

There are 4 universities involved in the joint teaching for the term:

  • ETH Zürich (ETHZ), with instructors Emilio Frazzoli, Andrea Censi, Jacopo Tani.
  • University of Montreal (UdeM), with instructor Liam Paull.
  • TTI-Chicago (TTIC), with instructor Matthew Walter.
  • National C T University (NCTU), with instructor Nick Wang.

This part of the Duckiebook describes all the information that is needed by the students of the four institutions.

Because of mathjax bug

General remarks

🔗

Andrea

The rules of Duckietown

🔗

The first rule of Duckietown

The first rule of Duckietown is: you don’t talk about Duckietown, using email.

Instead, we use a communication platform called Slack.

There is one exception: inquiries about “meta” level issues, such as course enrollment and other official bureaucratic issues can be communicated via email.

The second rule of Duckietown

The second rule of Duckietown is: be kind and respectful, and have fun.

The third rule of Duckietown

The third rule of Duckietown is: read the instructions carefully.

Do not blindly copy and paste.

Only run a command if you know what it does.

Synchronization between classes

🔗

At ETHZ, UdeM, TTIC, the class will be more-or-less synchronized. The materials are the same; there is some slight variation in the ordering.

Moreover, there will be some common groups for the projects.

The NCTU class is undergraduate level. Students will learn slightly simplified materials. They will not collaborate directly with the classes.

Accounts for students

🔗

To participate in Duckietown, students must use two accounts: Slack and Github.

Slack

🔗

You need a Slack account, for team discussion and organization.

Sign up link here:

Account naming convention

Github

🔗

Account naming convention

  • A Github account;

  • Membership in the Duckietown organization.

Accounts for all instructors and TAs

🔗

As an instructor/TA for the Fall 2017 class, in addition to the accounts above, these are two more accounts that you need.

Twist

🔗

Twist is used for class organization (such as TAs, logistics);

TODO:

Google docs

🔗

Google Docs is used to maintain TODOs and other coordination materials.

how to be authorized?

In particular:

  • This is the schedule: XXX
  • This is the calendar in which to annotate everything: XXX
Because of mathjax bug

Additional information for ETH Zürich students

🔗

Andrea

This section describes information specific for ETH Zürich students.

to write

Website

🔗

All really important information, such as deadlines, is in the authoritative website:

Duckiebox distribution

🔗

to write

Lab access

🔗

To write

The local TAs

🔗

to write

Because of mathjax bug

Additional information for UdeM students

🔗

Liam

to write

Because of mathjax bug

Additional information for TTIC students

🔗

Matt

to write

Because of mathjax bug

Additional information for NCTU students

🔗

Nick

to write

Because of mathjax bug
Because of mathjax bug
Because of mathjax bug
Because of mathjax bug

Milestone: ROS node working

🔗
Because of mathjax bug

Homework: Take and process a log

🔗
Because of mathjax bug

Milestone: Calibrated robot

🔗
Because of mathjax bug

Homework: Camera geometry

🔗
Because of mathjax bug

Milestone: Illumination invariance

🔗
Because of mathjax bug

Homework: Place recognition

🔗
Because of mathjax bug

Milestone: Lane following

🔗
Because of mathjax bug

Homework: localization

🔗
Because of mathjax bug

Milestone: Navigation

🔗
Because of mathjax bug

Homework: group forming

🔗
Because of mathjax bug

Milestone: Ducks in a row

🔗
Because of mathjax bug

Homework: Comparison of PID

🔗
Because of mathjax bug

Homework: RRT

🔗
Because of mathjax bug

Caffe tutorial

🔗
Because of mathjax bug

Milestone: Object Detection

🔗
Because of mathjax bug

Homework: Object Detection

🔗
Because of mathjax bug

Milestone: Semantic perception

🔗
Because of mathjax bug

Homework: Semantic perception

🔗
Because of mathjax bug

Milestone: Reacting to obstacles

🔗
Because of mathjax bug

Homework: Reacting to obstacles

🔗
Because of mathjax bug

Milestone: SLAM demo

🔗
Because of mathjax bug

Homework: SLAM

🔗
Because of mathjax bug

Milestone: fleet demo

🔗
Because of mathjax bug

Homework: fleet

🔗
Because of mathjax bug

Project proposals

🔗
Because of mathjax bug

Template of a project

🔗
Because of mathjax bug

Checklist for students

🔗
  • Have a Github account. See Chapter 109. See name conventions (TODO).
  • Be part of the Duckietown Github organization. You are sure only when you commit and push one change to one of our repositories.
  • Be part of the Duckietown Slack. See name conventions (TODO).

Checklist for TAs

🔗
  • Be signed up on
Because of mathjax bug

Packages - Infrastructure

🔗

to write

Because of mathjax bug
Because of mathjax bug

Package duckietown

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The duckietown meta package

Because of mathjax bug
Because of mathjax bug

Package duckietown_msgs

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package duckietown_msgs in package.xml.

Because of mathjax bug

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The easy_algo package

Because of mathjax bug

Package easy_algo

🔗

line_detector.easy_algo.yaml

interface: line_detector.LineDetectorInterface
description: |
    These are the line detectors.
tests:
- how to test it

my_line_detector.line_detector.yaml

description: |
    These are
code:
- ClassName
- param1: value1
  param2: value2
Because of mathjax bug

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The easy_logs package

Because of mathjax bug

Package easy_logs

🔗

line_detector.easy_algo.yaml

interface: line_detector.LineDetectorInterface
description: |
    These are the line detectors.
tests:
- how to test it

my_line_detector.line_detector.yaml

description: |
    These are
code:
- ClassName
- param1: value1
  param2: value2
Because of mathjax bug
Because of mathjax bug

Package easy_node

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

easy_node is a framework to make it easier to create and document ROS nodes.

The main idea is to provide a declarative approach to describe:

  • The node parameters;
  • The node’s subscriptions;
  • The node’s publishers;
  • The node’s assumptions (contracts).

The user describes subscriptions, publishers, and parameters in a YAML file.

The framework then automatically takes care of:

  • Calling the necessary boilerplate ROS commands for subscribing and publishing topics.
  • Loading and monitoring configuration.
  • Create the Markdown documentation that describes the nodes.
  • Provide a set of common functionality, such as benchmarking and monitoring latencies.

Using easy_node allows to cut 40%-50% of the code required for programming a node. For an example, see the package line_detector2, which contains a re-implementation of line_detector using the new framework.

Transition plan: The plan is to first use easy_node just for documenting the nodes. Then, later, convert all the nodes to use it.

YAML file format

🔗

For a node with the name my node, implemented in the file src/my node.py you must create a file by the name my node.easy_node.yamlsomewhere in the package.

The YAML file must contain 4 sections, each of which is a dictionary.

This is the smallest example of an empty configuration:

parameters: 
subscriptions: 
publishers: 
contracts:

parameters section: configuring parameters

🔗

This is the syntax:

parameters:
    name parameter:
        type: type
        desc: description
        default: default value

where:

  • type is one of float, int, bool, str.
  • description is a description that will appear in the documentation.
  • The optional field default gives a default value for the parameter.

For example:

parameters:
    k_d:
        type: float
        desc: The derivative gain.
        default: 1.02

publishers and subscriptions section

🔗

The syntax for describing subscribers is:

subscriptions:
    name subscription:
        topic: topic name
        type: message type
        desc: description

        queue_size: queue size
        latch: latch
        process: process

The parameters are as follows.

topic name is the name of the topic to subscribe.

message type is a ROS message type name, such as sensor_msgs/Joy. - description is a Markdown description string.

queue size, latch are optional parameters for ROS publishing/subscribing functions.

See the ROS documentation.

The optional parameter process, one of synchronous (default) or asynchronous describes whether to process the message in a synchronous or asynchronous way (in a separated thread).

The optional parameter timeout describes a timeout value. If no message is received for more than this value, the function on_timeout_subscription() is called.

implement this timeout functionality.

The syntax for describing publishers is similar; it does not have the the process and timeout value.

Example:

subscriptions:
    segment_list:
        topic: ~segment_list
        type: duckietown_msgs/SegmentList
        desc: Line detections
        queue_size: 1
        timeout: 3

publishers:
    lane_pose:
        topic: ~lane_pose
        type: duckietown_msgs/LanePose
        desc: Estimated pose
        queue_size: 1

Describing contracts

🔗

This is not implemented yet.

The idea is to have a place where we can describe constraints such as:

  • “This topic must publish at least at 30 Hz.”
  • “Panic if you didn’t receive a message for 2 seconds.”
  • “The maximum latency for this is 0.2 s”

Then, we can implement all these checks once and for all in a proper way, instead of relying on multiple broken implementations

Using the easy_node API

🔗

Initialization

🔗

Here is a minimal example of a node that conforms with the API:

from easy_node import EasyNode

class MyNode(EasyNode):

    def __init__(self):
        EasyNode.__init__(self, 'my_package', 'my_node')
        self.info('Initialized.')

if __name__ == '__main__':
    MyNode().spin()

The node class must derive from EasyNode. You need to tell EasyNode what is the package name and the node name.

To initialize, call the function spin().

The EasyNode class provides the following functions:

info()
debug()
error()

These are mapped to rospy.loginfo() etc.; they include the name of the node.

Using configuration parameters

🔗

This next example shows how to use configuration parameters.

First, create a file my_node.easy_node.yaml containing:

parameters:
    num_cells:
        desc: Number of cells.
        type: int
        default: 42
subscriptions: 
contracts: 
publishers:

Then, implement the method on_parameters_changed(). It takes two parameters:

  • first_time is a boolean that tells whether this is the first time that the function is called (initialization time).
  • updated is a set of strings that describe the set of parameters that changed. The first time, it contains the set of all parameters.

To access the parameter value, access self.config.parameter.

Example:

class MyNode():

    def __init__(self):
        EasyNode.__init__(self, 'my_package', 'my_node')

def on_parameters_changed(self, first_time, updated):
    if first_time:
        self.info('Initializing array for the first time.')
        self.cells = [0] * self.config.num_cells

    else:
        if 'num_cells' in updated:
            self.info('Number of cells changed.')
            self.cells = [0] * self.config.num_cells

if __name__ == '__main__':
    Node().spin()

EasyNode will monitor the ROS parameter server, and will call the function on_parameters_changed if the user changes any parameters.

Using subscriptions

🔗

To automatically subscribe to topics, add an entry in the subscriptions section of the YAML file.

For example:

subscriptions:
    joy:
        desc: |
            The `Joy.msg` from `joy_node` of the `joy` package.
            The vertical axis of the left stick maps to speed.
            The horizontal axis of the right stick maps to steering.
        type: sensor_msgs/Joy
        topic: ~joy
        timeout: 3.0

Then, implement the function on_received_name.

This function will be passed 2 arguments:

  • a context object; this can be used for benchmarking (Section 160.6).
  • the message object.

Example:

class MyNode():
    # ...

    def on_received_joy(self, context, msg):
        # This is called any time a message arrives
        self.info('Message received: %s' % msg)

Time-out

🔗

to implement

The function on_timeout_subscription() is called when there hasn’t been a message for the specified timeout interval.

class MyNode():
    # ...

    def on_timeout_joy(self, context, time_since):
        # This is called when we have not seen a message for a while
        self.error('No joystick received since %s s.' % time_since)

Publishers

🔗

The publisher object can be accessed at self.publishers.name. EasyNode has taken care of all the initialization for you.

For example, suppose we specify a publisher command using:

publishers:
    command:
        desc: The control command.
        type: duckietown_msgs/Twist2DStamped
        topic: ~car_cmd

Then we can use it as follows.

class MyNode():
    # ...

    def on_received_joy(self, context, msg):
        out = Twist2DStamped()
        out.header.stamp = 0
        out.v = 0
        out.omega = 0

        self.publishers.command.publish(out)

on_init() and on_shutdown()

🔗

Define the two methods on_init() and on_shutdown() to c

class MyNode(EasyNode):
    # ...
   def on_init(self):
        self.info('Step 1 - Initialized')

   def on_parameters_changed(self, first_time, changed):
        self.info('Step 2 - Parameters received')

   def on_shutdown(self):
        self.info('Step 3 - Preparing for shutdown.')

Note that on_init() is called before on_parameters_changed().

Configuration using easy_node: the user’s point of view

🔗

So far, we have seen how to use parameters from the node, but we did not talk about how to specify the parameters from the user’s point of view.

EasyNode introduces lots of flexibility compared to the legacy system.

Configuration file location

🔗

The user configuration is specified using files by the pattern

package_name-node_name.config name.config.yaml

where config name is a short string (e.g., baseline).

The files can be anywhere in:

  • The directory ${DUCKIETOWN_ROOT}/catkin_ws/src;

  • The directory ${DUCKIEFLEET_ROOT}.

Several config files can exist at the same time. For example, we could have somewhere:

line_detector-line_detector.baseline.config.yaml
line_detector-line_detector.fall2017.config.yaml
line_detector-line_detector.andrea.config.yaml

where the baseline versions are the baseline parameters, fall2017 are the parameters we are using for Fall 2017, and andrea are temporary parameters that the user is using.

However, there cannot be two configurations with the same filename e.g. two copies of line_detector-line_detector.baseline.config.yaml. In this case, EasyNode will raise an error.

implement this functionality.

Configuration file format

🔗

The format of the *.config.yaml file is as follows:

description: |
    description of what this configuration accomplishes
extends: [config name, config name]
values:
    parameter name: value
    parameter  name: value

The extends field (optional) is a list of string. It allows to use the specified configurations as the defaults for the current one.

For example, the file line_detector-line_detector.baseline.config.yaml could contain:

description: |
    These are the standard values for the line detector.
extends: []
values:
    img_size: [120,160]
    top_cutoff: 40

Configuration sequence

🔗

Which parameters are used depend on the configuration sequence.

The configuration sequence is a list of configuration names.

It can be specified by the environment variable DUCKIETOWN_CONFIG_SEQUENCE, using a colon-separated list of strings. For example:

$ export DUCKIETOWN_CONFIG_SEQUENCE=baseline:fall2017:andrea

The line above specifies that the configuration sequence is baseline, fall2017, andrea.

The system loads the configuration in order. First, it loads the baseline version. Then it loads the fall2017 version. If a value was already specified in the baseline version, it is overwritten. If a version does not exist, it is simply skipped.

If a parameter is not specified in any configuration, an error is raised.

Using this functionality, it is easy to have team-based customization and user-based customization.

There are two special configuration names:

  1. The configuration name “defaults” loads the defaults specified by the node. Note that the defaults are ignored otherwise.
  2. The configuration name “vehicle” expands to the name of the vehicle being used.

the vehicle part is not implemented yet.

Time-variant configuration

🔗

EasyNode allows to describe configuration that can change in time.

The use case for this is the configuration of calibration parameters:

  • Calibration parameters change with time.
  • We still want to access old calibration parameters, when processing logs.

The solution is to allow a date tag in the configuration name. The format for this is

package_name-node_name.config name.date.config.yaml

For example, we could have the files:

kinematics-kinematics.ferrari.20160404.config.yaml
kinematics-kinematics.ferrari.20170101.config.yaml

Given this, EasyNode will select the configuration to use intelligently. When reading from a bag file from 2016, the first configuration is going to be used; for logs in 2017, the second is going to be used.

not implemented yet.

Visualizing the configuration database

🔗

There are a few tolls used to visualize the configuration database.

easy_node desc: Describing a node

🔗

The command

$ rosrun easy_node desc package name node name

shows a description of the node, as specified in package name.node name.easy_node.yaml.

For example:

$ rosrun easy_node desc line_detector2 line_detector2

shows the following:

Configuration for node "line_detector_node2" in package "line_detector2"
========================================================================

 Parameters

    name                       type   default
    ----                       ----   -------
    en_update_params_interval  float  2.0
    top_cutoff                 int    (none)
    detector                   (n/a)  (none)
    img_size                   (n/a)  (none)
    verbose                    bool   True


 Subcriptions

    name       type                    topic       options         process
    ----       ----                    -----       -------         -------
    switch     BoolStamped             ~switch     queue_size = 1  synchronous
    image      CompressedImage         ~image      queue_size = 1  threaded
    transform  AntiInstagramTransform  ~transform  queue_size = 1  synchronous


 Publishers

    name              type         topic              options
    ----              ----         -----              -------
    color_segment     Image        ~colorSegment      queue_size = 1
    edge              Image        ~edge              queue_size = 1
    segment_list      SegmentList  ~segment_list      queue_size = 1
    image_with_lines  Image        ~image_with_lines  queue_size = 1

easy_node eval: Evaluating a configuration sequence

🔗

The program eval script allows to evaluate a certain configuration sequence.

The syntax is:

$ rosrun easy_node eval package name node name config sequence

The tool shows also which file is responsible for the value of each parameter.

For example, the command

$ rosrun easy_node eval line_detector2 line_detector_node2 defaults:andrea

evaluates the configuration for the line_detector_node2 node with the configuration sequence defaults:andrea.

The result is:

Configuration result for node `line_detector_node2` (package `line_detector2`)
The configuration sequence was ['defaults', 'baseline', 'andrea'].
The following is the list of parameters set and their origin:
  parameter                    value                              origin
  ---------                    -----                              ------
  en_update_params_interval    2.0                                defaults
  top_cutoff                   40                                 baseline
  detector                     - line_detector.LineDetectorHSV    baseline
                               - configuration:
                                   canny_thresholds: [80, 200]
                                   dilation_kernel_size: 3
                                   hough_max_line_gap: 1
                                   hough_min_line_length: 3
                                   hough_threshold: 2
                                   hsv_red1: [0, 140, 100]
                                   hsv_red2: [15, 255, 255]
                                   hsv_red3: [165, 140, 100]
                                   hsv_red4: [180, 255, 255]
                                   hsv_white1: [0, 0, 150]
                                   hsv_white2: [180, 60, 255]
                                   hsv_yellow1: [25, 140, 100]
                                   hsv_yellow2: [45, 255, 255]
  img_size                     [120, 160]                         baseline
  verbose                      true                               defaults

Note how we can tell which configuration file is responsible for setting each parameter.

easy_node summary: Describing and validating all configuration files

🔗

The program summary reads all the configuration files described in the repository and validates them against the node description.

If a configuration file refers to parameters that do not exist, the configuration file is established to be invalid.

The syntax is:

$ rosrun easy_node summary

For example, the output can be:

package name      node name              config_name    effective     extends    valid    error    description
line_detector2    line_detector_node2    baseline       2017-01-01    ()         yes               These are the standard values for t [..]

Benchmarking

🔗

EasyNode implements some simple timing statistics. These are accessed using the context object passed to the message received callbacks.

Here’s an example use, from line_detector2:

def on_received_image(self, context, image_msg):

    with context.phase('decoding'):
        ...

    with context.phase('resizing'):
        # Resize and crop image
        ...

    stats = context.get_stats()
    self.info(stats)

The idea is to enclose the different phases of the computation using the context manager phase(name).

A summary of the statistics can be accessed by using context.get_stats().

For example, this will print:

Last 24.4 s: received 734 (30.0 fps) processed 301 (12.3 fps) skipped 433 (17.7 fps) (59 %)
            decoding | total latency  25.5 ms | delta wall   20.7 ms | delta clock  20.7 ms
            resizing | total latency  26.6 ms | delta wall    0.8 ms | delta clock   0.7 ms
          correcting | total latency  29.1 ms | delta wall    2.2 ms | delta clock   2.2 ms
           detection | total latency  47.7 ms | delta wall   18.2 ms | delta clock  21.3 ms
    preparing-images | total latency  55.0 ms | delta wall    7.0 ms | delta clock   7.0 ms
          publishing | total latency  55.5 ms | delta wall    0.1 ms | delta clock   0.1 ms
          draw-lines | total latency  59.7 ms | delta wall    4.0 ms | delta clock   3.9 ms
    published-images | total latency  61.2 ms | delta wall    0.9 ms | delta clock   0.8 ms
pub_edge/pub_segment | total latency  86.3 ms | delta wall   24.7 ms | delta clock  24.0 ms

Automatic documentation generation

🔗

EasyNode generated the documentation automatically from the *.easy_node.yaml files.

Note that this can be used independently of the fact that the node implements the EasyNode API. So, we can use this EasyNode functionality also to document the legacy nodes.

To generate the docs, use this command:

$ rosrun easy_node generate_docs

For each node documented using a *.easy_node.yaml, this generates a Markdown file called “node name-easy_node-autogenerated.md” in the package directory.

The contents are enclosed in a div with ID #package name-node name-autogenerated.

The intended use is that this can be used to move the contents to the place in the documentation using the move-here tag.

For example, in the README.md of the joy_mapper package, we have:

## Node `joy_mapper_node`

<move-here src="#joy_mapper-joy_mapper_node-autogenerated"/>

The result can be seen at Chapter 166.

Parameters and services defined for all packages

🔗

(Generated from configuration easy_node.easy_node.yaml.)

These are properties common to all nodes.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Other ideas

🔗

(Add here other ideas that we can implement.)

Because of mathjax bug
Because of mathjax bug

Package what_the_duck

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

What the duck?

what-the-duck is a program that tests dozens of configuration inconsistencies that can happen on a Duckiebot.

What the duck

🔗

To use it, first compile the repository, and then run:

$ ./what-the-duck

Adding more tests to what-the-duck

🔗

The idea is to add to what-the-duck all the tests that can be automated.

The documentation about to do that is not ready yet.

Tests already added

🔗

Here is the list of tests already added:

✓  Camera is detected
✓  Scipy is installed
✓  sklearn is installed
✓  Date is set correctly
✓  Not running as root
✓  Not running as ubuntu
✓  Member of group sudo
✓  Member of group input
✓  Member of group video
✓  Member of group i2c
✓  ~/.ssh exists
✓  ~/.ssh permissions
✓  ~/.ssh/config exists
✓  SSH option HostKeyAlgorithms is set
✓  At least one key is configured.
✓  ~/.ssh/authorized_keys exists
✓  Git configured
✓  Git email set
✓  Git name set
✓  Git push policy set
✓  Edimax detected
✓  The hostname is configured
✓  /etc/hosts is sane
✓  Correct kernel version
✓  Messages are compiled
✓  Shell is bash
✓  Working internet connection
✓  Github configured
✓  Joystick detected
✓  Environment variable DUCKIETOWN_ROOT
✓  ${DUCKIETOWN_ROOT} exists
✓  Environment variable DUCKIETOWN_FLEET
✓  ${DUCKIETOWN_FLEET} exists
✓  ${DUCKIETOWN_FLEET}/scuderia.yaml exists
✓  ${DUCKIETOWN_FLEET}/scuderia.yaml is valid
✓  machines file is valid
✓  Wifi network configured
✓  Python: No CamelCase
✓  Python: No tab chars
✓  Python:  No half merges

List of tests to add

🔗

Please add below any configuration test that can be automated:

  • Editor is set to vim.

  • Syntax on in ~/.vimrc

  • They put the right MAC address in the network configuration

  • Ubuntu user is in group video, input, i2c (even if run from other user.)

  • There is at least X.YGB of free disk space.

  • If the SD is larger than 8GB, the disk has been resized.

Because of mathjax bug

Packages - Lane control

🔗

to write

Because of mathjax bug
Because of mathjax bug

Package adafruit_drivers

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package adafruit_drivers in package.xml.

These are the Adafruit drivers.

What is the original location of this package?

Because of mathjax bug
Because of mathjax bug

Package anti_instagram

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package anti_instagram in package.xml.

Unit tests integrated with rostest

🔗

Unit tests are integrated with rostest.

To run manually, use:

$ rostest anti_instagram antiinstagram_correctness_test.test
$ rostest anti_instagram antiinstagram_stub_test.test
$ rostest anti_instagram antiinstagram_performance_test.test

Unit tests needed external files

🔗

These are other unittest that require the logs in DUCKIETOWN_DATA:

$ rosrun anti_instagram annotations_test.py

Node anti_instagram_node

🔗

(Generated from configuration anti_instagram_node.easy_node.yaml.)

Missing node description in anti_instagram_node.easy_node.yaml.

Parameters

🔗

Parameter publish_corrected_image: bool; default value: False

Whether to compute and publish the corrected image.

Subscriptions

🔗

Subscription image: topic ~uncorrected_image (CompressedImage)

This is the compressed image to read.

Subscription click: topic ~click (BoolStamped)

Activate the calibration phase with this switch.

Publishers

🔗

Publisher image: topic ~corrected_image (Image)

The corrected image.

Publisher health: topic ~colorSegment (AntiInstagramHealth)

The health of the process.

Publisher transform: topic ~transform (AntiInstagramTransform)

The computed transform.

Because of mathjax bug
Because of mathjax bug

Package dagu_car

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package dagu_car in package.xml.

Node forward_kinematics_node

🔗

(Generated from configuration forward_kinematics_node.easy_node.yaml.)

Missing node description in forward_kinematics_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node inverse_kinematics_node

🔗

(Generated from configuration inverse_kinematics_node.easy_node.yaml.)

Missing node description in inverse_kinematics_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node velocity_to_pose_node

🔗

(Generated from configuration velocity_to_pose_node.easy_node.yaml.)

Missing node description in velocity_to_pose_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node car_cmd_switch_node

🔗

(Generated from configuration car_cmd_switch_node.easy_node.yaml.)

Missing node description in car_cmd_switch_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node wheels_driver_node

🔗

(Generated from configuration wheels_driver_node.easy_node.yaml.)

Missing node description in wheels_driver_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node wheels_trimmer_node

🔗

(Generated from configuration wheels_trimmer_node.easy_node.yaml.)

Missing node description in wheels_trimmer_node.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Because of mathjax bug
Because of mathjax bug

Package ground_projection

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package ground_projection in package.xml.

Node ground_projection_node

🔗

(Generated from configuration ground_projection.easy_node.yaml.)

Missing node description in ground_projection.easy_node.yaml.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Because of mathjax bug
Because of mathjax bug

Package joy_mapper

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The joy_mapper package for duckietown. Takes sensor_msgs.Joy and convert it to duckietown_msgs.CarControl.

Testing

🔗

Connect joystick.

Run:

$ roslaunch launch/joy_mapper_test.launch

The robot should move when you push buttons.

Dependencies

🔗
  • rospy
  • sensor_msgs: for the Joy.msg
  • duckietown_msgs: for the CarControl.msg

Node joy_mapper_node2

🔗

(Generated from configuration joy_mapper_node2.easy_node.yaml.)

This node takes a sensor_msgs/Joy.msg and converts it to a duckietown_msgs/CarControl.msg.

It publishes at a fixed interval with a zero-order hold.

Parameters

🔗

Parameter v_gain: float; default value: 0.41

Missing description for entry “v_gain”.

Parameter omega_gain: float; default value: 8.3

Missing description for entry “omega_gain”.

Parameter bicycle_kinematics: int; default value: 0

Missing description for entry “bicycle_kinematics”.

Parameter simulated_vehicle_length: float; default value: 0.18

Missing description for entry “simulated_vehicle_length”.

Parameter steer_angle_gain: int; default value: 1

Missing description for entry “steer_angle_gain”.

Subscriptions

🔗

Subscription joy: topic joy (Joy)

The Joy.msg from joy_node of the joy package. The vertical axis of the left stick maps to speed. The horizontal axis of the right stick maps to steering.

Publishers

🔗

Publisher avoidance: topic ~start_avoidance (BoolStamped)

Missing description for entry “avoidance”.

Publisher car_cmd: topic ~car_cmd (Twist2DStamped)

Missing description for entry “car_cmd”.

Publisher joy_override: topic ~joystick_override (BoolStamped)

Missing description for entry “joy_override”.

Publisher parallel_autonomy: topic ~parallel_autonomy (BoolStamped)

Missing description for entry “parallel_autonomy”.

Publisher e_stop: topic wheels_driver_node/emergency_stop (BoolStamped)

Missing description for entry “e_stop”.

Publisher anti_instagram: topic anti_instagram_node/click (BoolStamped)

Missing description for entry “anti_instagram”.

Because of mathjax bug
Because of mathjax bug

Package lane_control

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package lane_control in package.xml.

lane_controller_node

🔗

(Generated from configuration lane_controller_node.easy_node.yaml.)

there is some very funny business inside. It appears that k_d and k_theta are switched around.

Parameters

🔗

Parameter k_theta: float

Proportional gain for $\theta$.

Parameter theta_thres: float

Maximum desired $\theta$.

Parameter d_offset: float

A configurable offset from the lane position.

Parameter d_thres: float

Cap for error in $d$.

Parameter v_bar: float

Nominal linear velocity (m/s).

Parameter k_d: float

Propertional gain for $d$.

Subscriptions

🔗

Subscription lane_reading: topic ~lane_pose (LanePose)

Missing description for entry “lane_reading”.

Publishers

🔗

Publisher car_cmd: topic ~car_cmd (Twist2DStamped)

Missing description for entry “car_cmd”.

Because of mathjax bug
Because of mathjax bug

Package lane_filter

🔗

Liam

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package lane_filter in package.xml.

lane_filter_node

🔗

(Generated from configuration lane_filter_node.easy_node.yaml.)

Missing node description in lane_filter_node.easy_node.yaml.

Parameters

🔗

Parameter peak_val: float; default value: 10.0

Missing description for entry “peak_val”.

Parameter l_max: float; default value: 2.0

Missing description for entry “l_max”.

Parameter lanewidth: float; default value: 0.4

Missing description for entry “lanewidth”.

Parameter mean_d_0: float; default value: 0.0

Missing description for entry “mean_d_0”.

Parameter min_max: float; default value: 0.3

Expressed in nats.

Parameter d_max: float; default value: 0.5

Missing description for entry “d_max”.

Parameter use_distance_weighting: bool; default value: False

For use of distance weighting (dw) function.

Parameter linewidth_white: float; default value: 0.04

Missing description for entry “linewidth_white”.

Parameter cov_omega: float; default value: 0.01

Angular velocity “input”.

which units?

Parameter use_max_segment_dist: bool; default value: False

For use of maximum segment distance.

Parameter delta_d: float; default value: 0.02

(meters)

Parameter min_segs: int; default value: 10

For use of minimum segment count.

Parameter phi_min: float; default value: -1.5707

Missing description for entry “phi_min”.

Parameter sigma_d_0: float; default value: 0.0

Missing description for entry “sigma_d_0”.

Parameter phi_max: float; default value: 1.5707

Missing description for entry “phi_max”.

Parameter zero_val: float; default value: 1.0

Missing description for entry “zero_val”.

Parameter delta_phi: float; default value: 0.0

(radians)

Parameter l_peak: float; default value: 1.0

Missing description for entry “l_peak”.

Parameter cov_v: float; default value: 0.5

Linear velocity “input”.

which units?

Parameter sigma_phi_mask: float; default value: 0.05

Missing description for entry “sigma_phi_mask”.

Parameter sigma_d_mask: float; default value: 0.05

Missing description for entry “sigma_d_mask”.

Parameter mean_phi_0: float; default value: 0.0

Missing description for entry “mean_phi_0”.

Parameter sigma_phi_0: float; default value: 0.0

Missing description for entry “sigma_phi_0”.

Parameter d_min: float; default value: -0.7

Missing description for entry “d_min”.

Parameter linewidth_yellow: float; default value: 0.02

Missing description for entry “linewidth_yellow”.

Parameter use_min_segs: bool; default value: False

For use of minimum segment count.

Parameter use_propagation: bool; default value: False

For propagation.

Parameter max_segment_dist: float; default value: 1.0

For use of maximum segment distance.

Subscriptions

🔗

Subscription velocity: topic ~velocity (Twist2DStamped)

Missing description for entry “velocity”.

Subscription segment_list: topic ~segment_list (SegmentList)

Missing description for entry “segment_list”.

Publishers

🔗

Publisher belief_img: topic ~belief_img (Image)

Missing description for entry “belief_img”.

Publisher switch: topic ~switch (BoolStamped)

Missing description for entry “switch”.

Publisher lane_pose: topic ~lane_pose (LanePose)

Missing description for entry “lane_pose”.

Publisher entropy: topic ~entropy (Float32)

Missing description for entry “entropy”.

Publisher in_lane: topic ~in_lane (BoolStamped)

Missing description for entry “in_lane”.

Because of mathjax bug
Because of mathjax bug

Package line_detector2

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package line_detector2 in package.xml.

This is a re-implementation of the package line_detector using the new facilities provided by easy_node.

Testing the line detector using visual inspection

🔗

The following are instructions to test the line detector from bag files.

You can run from a bag with the following:

laptop $ roslaunch line_detector line_detector2_bag veh:=vehicle bagin:=bag in bagout:=bag out verbose:=true

Where:

  • bag in is the absolute path of the input bag.
  • vehicle is the name of the vehicle that took the log.
  • bag out is the absolute path if the output bag.

you always need to use absolute paths for bag files.

You can let this run for a few seconds, then stop using Ctrl-C.

You can then inspect the result using:

$ roscore &
$ rosbag play -l bag out
$ rviz &

In rviz click “add”, click “by topic” tab, expand “line_detector” and click “image_with_lines”.

Observe on the result that:

  1. There are lots of detections.
  2. Predominantly white detections (indicated in black) are on white lines, yellow detections (shown in blue) are on blue lines, and red detections (shown in green) are on red lines.

These are some sample logs on which to try:

$ wget -O 160122-manual1_ferrari.bag https://www.dropbox.com/s/8bpi656j7qox5kv?dl=1

https://www.dropbox.com/s/vwznjke4xvnhi9o/160122_manual2-ferrari.bag?dl=1

https://www.dropbox.com/s/y7uljl98punj0mp/160122_manual3_corner-ferrari.bag?dl=1

https://www.dropbox.com/s/d4n9otmlans4i62/160122-calibration-good_lighting-tesla.bag?dl=1

Sample output:

From cmd:roslaunch duckietown camera.launch veh:=${VEHICLE_NAME}
[INFO] [WallTime: 1453839555.948481] [LineDetectorNode] number of white lines = 14
[INFO] [WallTime: 1453839555.949102] [LineDetectorNode] number of yellow lines = 33
[INFO] [WallTime: 1453839555.986520] [LineDetectorNode] number of white lines = 18
[INFO] [WallTime: 1453839555.987039] [LineDetectorNode] number of yellow lines = 34
[INFO] [WallTime: 1453839556.013252] [LineDetectorNode] number of white lines = 14
[INFO] [WallTime: 1453839556.013857] [LineDetectorNode] number of yellow lines = 29
[INFO] [WallTime: 1453839556.014539] [LineDetectorNode] number of red lines = 2
[INFO] [WallTime: 1453839556.047944] [LineDetectorNode] number of white lines = 18
[INFO] [WallTime: 1453839556.048672] [LineDetectorNode] number of yellow lines = 28
[INFO] [WallTime: 1453839556.049534] [LineDetectorNode] number of red lines = 2
[INFO] [WallTime: 1453839556.081400] [LineDetectorNode] number of white lines = 13
[INFO] [WallTime: 1453839556.081944] [LineDetectorNode] number of yellow lines = 34
[INFO] [WallTime: 1453839556.082479] [LineDetectorNode] number of red lines = 1

The output from rviz looks like Figure 61.

RViz output

Quantitative tests

🔗

Something more quantitative (to be filled in by Liam or Hang)

line_detector_node2

🔗

(Generated from configuration line_detector_node2.easy_node.yaml.)

This is a rewriting of line_detector_node using the EasyNode framework.

Parameters

🔗

Parameter top_cutoff: int

This parameter decides how much of the image we should cut off. This is a performance improvement.

Parameter line_detector: str

This is the instance of line_detector to use.

Parameter img_size: not known

Missing description for entry “img_size”.

Parameter verbose: bool; default value: True

Whether the node is verbose or not. If set to True, the node will write timing statistics to the log.

Subscriptions

🔗

Subscription switch: topic ~switch (BoolStamped)

This is a switch that allows to control the activity of this node. If the message is true, the node becomes active. If false, it switches off. The node starts as active.

Subscription image: topic ~image (CompressedImage)

This is the compressed image to read. Note that it takes a long time to simply decode the image JPG.

The data is processed asynchronously in a different thread.

Subscription transform: topic ~transform (AntiInstagramTransform)

The anti-instagram transform to apply. See Chapter 163.

Publishers

🔗

Publisher color_segment: topic ~colorSegment (Image)

Missing description for entry “color_segment”.

Publisher edge: topic ~edge (Image)

Missing description for entry “edge”.

Publisher segment_list: topic ~segment_list (SegmentList)

Missing description for entry “segment_list”.

Publisher image_with_lines: topic ~image_with_lines (Image)

Missing description for entry “image_with_lines”.

Because of mathjax bug
Because of mathjax bug

Package line_detector

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package line_detector in package.xml.

This package is being replaced by the cleaned-up version, line_detector2. Do not write documentation here.

However, at the moment, all the launch files still call this one.

Because of mathjax bug
Because of mathjax bug

Package pi_camera

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package pi_camera in package.xml.

Node camera_node_sequence

🔗

(Generated from configuration camera_node_sequence.easy_node.yaml.)

Camera driver, second approach.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node camera_node_continuous

🔗

(Generated from configuration camera_node_continuous.easy_node.yaml.)

Camera driver.

Parameters

🔗

Parameter res_w: int; default value: 320

Resolution (width)

Parameter framerate: float; default value: 60.0

Frame rate

Parameter res_h: int; default value: 200

Resolution (height)

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

Publisher image_compressed: topic ~image/compressed" (CompressedImage)

Missing description for entry “image_compressed”.

Node decoder_node

🔗

(Generated from configuration decoder_node.easy_node.yaml.)

A node that decodes a compressed image into a regular image. This is useful so that multiple nodes that need to use the image do not do redundant computaon.

Parameters

🔗

Parameter publish_freq: float; default value: 1.0

Frequency at which to publish (Hz).

Subscriptions

🔗

Subscription compressed_image: topic ~compressed_image (CompressedImage)

The image to decode.

Subscription switch: topic ~switch (BoolStamped)

Switch to turn on or off. The node starts as active.

Publishers

🔗

Publisher raw: topic ~image/raw (Image)

The decoded image.

Node img_process_node

🔗

(Generated from configuration img_process_node.easy_node.yaml.)

Apparently, a template, or a node never finished.

Parameters

🔗

No parameters defined.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Node cam_info_reader_node

🔗

(Generated from configuration cam_info_reader_node.easy_node.yaml.)

Publishes a CameraInfo message every time it receives an image.

Parameters

🔗

Parameter image_type: str; default value: 'compressed'

Missing description for entry “image_type”.

Parameter config: str; default value: 'baseline'

Missing description for entry “config”.

Parameter cali_file_name: str; default value: 'default'

Missing description for entry “cali_file_name”.

Subscriptions

🔗

Subscription compressed_image: topic ~compressed_image (CompressedImage)

If image_type is “compressed” then it’s CompressedImage, otherwise Image.

Publishers

🔗

Publisher camera_info: topic ~camera_info (CameraInfo)

Missing description for entry “camera_info”.

Because of mathjax bug

Packages - Indefinite navigation

🔗

to write

Because of mathjax bug
Because of mathjax bug

AprilTags library

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

Michael Kaess

Hordur Johannson

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

A catkin version of the C++ apriltags library

Detect April tags (2D bar codes) in images; reports unique ID of each detection, and optionally its position and orientation relative to a calibrated camera.

See examples/apriltags_demo.cpp for a simple example that detects April tags (see tags/pdf/tag36h11.pdf) in laptop or webcam images and marks any tags in the live image.

Ubuntu dependencies: sudo apt-get install subversion cmake libopencv-dev libeigen3-dev libv4l-dev

Mac dependencies: sudo port install pkgconfig opencv eigen3

Uses the pods build system in connection with cmake, see: http://sourceforge.net/p/pods/

Michael Kaess October 2012


AprilTags were developed by Professor Edwin Olson of the University of Michigan. His Java implementation is available on this web site: http://april.eecs.umich.edu.

Olson’s Java code was ported to C++ and integrated into the Tekkotsu framework by Jeffrey Boyland and David Touretzky.

See this Tekkotsu wiki article for additional links and references: http://wiki.tekkotsu.org/index.php/AprilTags


This C++ code was further modified by Michael Kaess (kaess@mit.edu) and Hordur Johannson (hordurj@mit.edu) and the code has been released under the LGPL 2.1 license.

  • converted to standalone library
  • added stable homography recovery using OpenCV
  • robust tag code table that does not require a terminating 0 (omission results in false positives by illegal codes being accepted)
  • changed example tags to agree with Ed Olson’s Java version and added all his other tag families
  • added principal point as parameter as in original code - essential for homography
  • added some debugging code (visualization using OpenCV to show intermediate detection steps)
  • added fast approximation of arctan2 from Ed’s original Java code
  • using interpolation instead of homography in Quad: requires less homography computations and provides a small improvement in correct detections

todo: - significant speedup could be achieved by performing image operations using OpenCV (Gaussian filter, but also operations in TagDetector.cc) - replacing arctan2 by precomputed lookup table - converting matrix operations to Eigen (mostly for simplifying code, maybe some speedup)

Because of mathjax bug
Because of mathjax bug

Package apriltags_ros

🔗

AprilTags for ROS.

Build Status

Package information

🔗

Link to package on Github

Essentials

🔗

Mitchell Wills

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

A package that provides a ROS wrapper for the apriltags C++ package

Because of mathjax bug
Because of mathjax bug

Package fsm

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The finite state machine coordinates the modes of the car.

Node fsm_node

🔗

(Generated from configuration fsm_node.easy_node.yaml.)

Note that this node publishes on many topics according to the configuration:

for node_name, topic_name in nodes.items():
    self.pub_dict[node_name] = rospy.Publisher(topic_name, BoolStamped, ...)

Parameters

🔗

Parameter states: dict; default value: ``

Missing description for entry “states”.

Parameter nodes: not known

Missing description for entry “nodes”.

Parameter initial_state: str; default value: ''

Missing description for entry “initial_state”.

Parameter global_transitions: dict; default value: ``

Missing description for entry “global_transitions”.

Parameter events: dict; default value: ``

Missing description for entry “events”.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

Publisher mode: topic ~mode (FSMState)

Missing description for entry “mode”.

Because of mathjax bug
Because of mathjax bug

Package indefinite_navigation

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package indefinite_navigation in package.xml.

Because of mathjax bug
Because of mathjax bug

Package intersection_control

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The intersection_control package implements a dead reckoning controller until we do something smarter.

Because of mathjax bug
Because of mathjax bug

Package stop_line_filter

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package stop_line_filter in package.xml.

Because of mathjax bug

Packages - Localization and planning

🔗

to write

Because of mathjax bug
Because of mathjax bug

Package duckietown_description

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package duckietown_description in package.xml.

Because of mathjax bug
Because of mathjax bug

Package localization

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package localization in package.xml.

Because of mathjax bug

Packages - Coordination

🔗

to write

Because of mathjax bug
Because of mathjax bug

Package led_detection

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package led_detection in package.xml.

LED detector

🔗

Pick your favourite duckiebot as the observer-bot. Refer to it as robot name for this step. If you are in good company, this can be tried on all the available duckiebots. First, activate the camera on the observer-bot:

$ roslaunch duckietown camera.launch veh:=robot name

In a separate terminal, fire up the LED detector and the custom GUI by running:

$ roslaunch led_detector LED_detector_with_gui.launch veh:=robot name

to operate without a GUI:

laptop $ roslaunch led_detector LED_detector.launch veh:=robot name

The LED_detector_node will be launched on the robot, while LED_visualizer (a simple GUI) will be started on your laptop. Make sure the camera image from the observer-bot is visualized and updated in the visualizer (tip: check that your camera cap is off).

Hit on Detect and wait to trigger a detection. This will not have any effect if LED_detector_node is not running on the duckiebot (it is included in the above launch file). After the capture and processing phases, the outcome will look like:

The red numbers represent the frequencies directly inferred from the camera stream, while the selected detections with the associated signaling frequencies will be displayed in green. You can click on the squares to visualize the brightness signals and the Fourier amplitude spectra of the corresponding cells in the video stream. You can also click on the camera image to visualize the variance map.

Unit tests

🔗

To run the unit tests for the LED detector, you need to have the F23 rosbags on you hard disk. These bag files should be synced from [this dropbox link] (https://www.dropbox.com/sh/5kx8qwgttu69fhr/AAASLpOVjV5r1xpzeW7xWZh_a?dl=0).

For the test to locate the bag files, you should have the DUCKIETOWN_DATA environment variable set, pointing to the location of you duckietown-data folder. This can be achieved by:

$ export DUCKIETOWN_DATA=local-path-to-duckietown-data-folder

All the available tests are specified in file all_tests.yaml in the scripts/ folder of the package led_detection in the duckietown ROS workspace. To run these, use the command:

$ rosrun led_detection unittests.py algorithm name-of-test

Currently, algorithm can be either ‘baseline’ or ‘LEDDetector_plots’ to also display the plot in the process.

To run all test with all algorithms, execute:

$ rosrun led_detection unittests.py '*' '*'

More in general:

$ rosrun led_detection unittests.py tests algorithms

where:

  • tests is a comma separated list of algorithms. May use “*”.
  • algorithms is a comma separated list of algorithms. May use “*”.

The default algorithm is called “baseline”, and its tests are invoked using:

$ rosrun led_detection <script> '*' 'baseline'
Because of mathjax bug
Because of mathjax bug

Package led_emitter

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

description for led_emitter package.

In depth

🔗

The coordination team will use 3 signals: CAR_SIGNAL_A, CAR_SIGNAL_B, CAR_SIGNAL_C. To test the LED emitter with your joystick, run the following command:

$ roslaunch led_joy_mapper led_joy_with_led_emitter_test.launch veh:=robot name

This launches the joy controller, the mapper controller, and the led emitter nodes. You should not need to run anything external for this to work. Use the joystick buttons A, B and C to change your duckiebot’s LED’s blinking frequency.

Button A broadcasts signal CAR_SIGNAL_A (2.8hz), button B broadcasts signal CAR_SIGNAL_B (4.1hz), and button CAR_SIGNAL_C (Y on the controller) broadcasts signal C(5hz).The LB button will make the LEDs all white, the RB button will make some LEDs blue and some LEDs green, and the logitek button (middle button) will make the LEDs all red

Repeat this for each vehicle at the intersection that you wish to be blinking. Use previous command replacing robot name the names of the vehicles and try command different blinking patterns on different duckiebots.

(optional tests) For a grasp of the low level LED emitter, run:

$ roslaunch led_emitter led_emitter_node.launch veh:=robot name

You can then publish to the topic manually by running the following command in another screen on the duckiebot:

$ rostopic pub /robot name/led_emitter_node/change_to_state std_msgs/Float32 float-value

Where float-value is the desired blinking frequency, e.g. 1.0, .5, 3.0, etc. If you wish to run the LED emitter test, run the following:

$ roslaunch led_emitter led_emitter_node_test.launch veh:=robot name

This will cycle through frequencies of 3.0hz, 3.5hz, and 4hz every 5 seconds. Once done, kill everything and make sure you have joystick control as described above.

Because of mathjax bug
Because of mathjax bug

Package led_interpreter

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package led_interpreter in package.xml.

Because of mathjax bug
Because of mathjax bug

Package led_joy_mapper

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package led_joy_mapper in package.xml.

Because of mathjax bug
Because of mathjax bug

Package rgb_led

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package rgb_led in package.xml.

Demos

🔗

To test the traffic light:

$ rosrun rgb_led blink trafficlight4way

Fancy test:

$ rosrun rgb_led blink trafficlight4way

To do other tests:

$ rosrun rgb_led blink
Because of mathjax bug
Because of mathjax bug

Package traffic_light

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package traffic_light in package.xml.

Because of mathjax bug

Packages - Additional functionality

🔗

to write

Because of mathjax bug
Because of mathjax bug

Package mdoap

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The mdoap package which handles object recognition and uses ground projection to estimate distances of objects for duckie safety. Also contains controllers for avoiding said obstacles

Because of mathjax bug
Because of mathjax bug

Package parallel_autonomy

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

description for the parallel autonomy package

Because of mathjax bug
Because of mathjax bug

Package vehicle_detection

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package vehicle_detection in package.xml.

Because of mathjax bug

Packages - Templates

🔗

These are templates.

Because of mathjax bug
Because of mathjax bug

Package pkg_name

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The package pkg_name is a template for ROS packages.

For the tutorial, see Chapter 115.

Because of mathjax bug
Because of mathjax bug

Package rostest_example

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package rostest_example in package.xml.

Because of mathjax bug

Packages - Convenience

🔗

These packages are convenience packages that group together launch files and tests.

Because of mathjax bug
Because of mathjax bug

Package duckie_rr_bridge

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The duckie_rr_bridge package. Creates a Robot Raconteur Service to drive the Duckiebot.

Because of mathjax bug
Because of mathjax bug

Package duckiebot_visualizer

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package duckiebot_visualizer in package.xml.

Node duckiebot_visualizer

🔗

(Generated from configuration duckiebot_visualizer.easy_node.yaml.)

Missing node description in duckiebot_visualizer.easy_node.yaml.

Parameters

🔗

Parameter veh_name: str; default value: 'megaman'

Missing description for entry “veh_name”.

Subscriptions

🔗

Subscription seg_list: topic ~segment_list (SegmentList)

Missing description for entry “seg_list”.

Publishers

🔗

Publisher pub_seg_list: topic ~segment_list_markers (MarkerArray)

Missing description for entry “pub_seg_list”.

Because of mathjax bug
Because of mathjax bug

Package duckietown_demos

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

description of duckietown_demos

Because of mathjax bug
Because of mathjax bug

Package duckietown_logs

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package duckietown_logs in package.xml.

Misc

🔗

Until we fix the dependencies:

sudo pip install SystemCmd==1.2 ros_node_utils==1.0 ConfTools==1.8 QuickApp==1.2.2

sudo apt-get install -y  mplayer mencoder

sudo add-apt-repository ppa:mc3man/trusty-media
sudo apt-get update
sudo apt-get install -y ffmpeg gstreamer0.10-ffmpeg
Because of mathjax bug
Because of mathjax bug

Package duckietown_unit_test

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The duckietown_unit_test meta package contains all the unit test launch files for Duckietown.

Because of mathjax bug
Because of mathjax bug

Package veh_coordinator

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The simple vehicle coordination package

I think is used to fake the vehicle coordination for the FSM.

Because of mathjax bug

Packages - To sort

🔗

We need to decide where these packages go.

Because of mathjax bug

Packages - Failed projects

🔗

These packages are abandoned failed projects.

Because of mathjax bug
Because of mathjax bug

Package bag_stamper

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package bag_stamper in package.xml.

Node bag_stamper_node

🔗

(Generated from configuration bag_stamper_node.easy_node.yaml.)

Missing node description in bag_stamper_node.easy_node.yaml.

Parameters

🔗

Parameter bagout: str; default value: None

Missing description for entry “bagout”.

Parameter topicin: str; default value: 'wheels_driver/wheels_cmd'

Missing description for entry “topicin”.

Parameter bagin: str

Missing description for entry “bagin”.

Parameter topicout: bool; default value: True

Missing description for entry “topicout”.

Subscriptions

🔗

No subscriptions defined.

Publishers

🔗

No publishers defined.

Because of mathjax bug
Because of mathjax bug

Package kinematics

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package kinematics in package.xml.

So many nodes here! Which ones are useful?

Because of mathjax bug
Because of mathjax bug

Package visual_odometry

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package visual_odometry in package.xml.

Because of mathjax bug

Package mouse_encoder

🔗

Use a mouse as encoder. Requires read permission to /dev/input/mice.

Publish Topic

🔗
  • mouse_encoder/tick: geometry_msg/Point message with number of ticks in the x and y direction.

Parameters

🔗
  • ~dev_path: Default to /dev/input/mice. Point to the device path of the mouse.

Getting access to /dev/input/mice.

🔗

Create a group named input:

$ sudo groupadd input

Add yourself to the input group:

$ sudo adduser your_user_name input

Log out and log back in for the change to take effect.

Put all devices under /dev/input/ into the input group to grant the group read/write permission. Can be done by adding a file name 99-pure-data.rules under /etc/udev/rules.d with the following line:

SUBSYSTEM=="input", GROUP="input", MODE="660"

Reboot for the rule to take effect.

Because of mathjax bug

Package simcity - Map Editor Version 0.1

🔗

All ./ references point to duckietown(Software)/catkin_ws/src/simcity A good reference for duckietown packages in general is catkin_ws/src/pkg_name/howto.md

How to run the map editor

🔗

(V0.1)

Inside ./launch is basic_map_tiler.launch. Ensure that the map file’s path is correct for your machine. We start simcity, given a specific map file. We also start rviz, ROS’ common gui.

How to edit the map

🔗

(V0.1)

The map is contained in ./maps as a YAML file. map.yaml is a small example of some circular streets, and censi_map.yaml is the map of the duckietown currently up and running.

What am I looking at, anyway?

🔗

(V0.1)

The magenta arrows point in the direction of traffic. These arrows are lines indicating where traffic flows.

What else is there to do?

🔗

(V0.1)

Lots of things. This part is mostly for rmata (1/11/16)

(1) Beautify it. Arrows are straight and ugly. Roads in duckietown can be curved, have not-so-subtle lane markings, stop signs, grass, and potentially cones and duckies.....

(2) Make it interactive. MarkerArrays consist of Markers. What does an InteractiveMarker consist of?

(3) Establish consistency and validation when adding a tile to a map. This would involve: - checking node positions at adjacent tiles - multiplying the sparse lane matrices and checking that number of lanes is consistent - having a perhaps separate node receive messages from the interactive server, or the basic_map_tiler node, and doing these computations for each change

Because of mathjax bug

Package slam

🔗
Because of mathjax bug

Package street_name_detector

🔗
Because of mathjax bug
Because of mathjax bug

Package adafruit_imu

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The Adafruit IMU package for duckietown. Reads sensor data from adafruit IMU and publishes it to sensor_msgs.Imu and sensor_msgs.MagneticField.

Testing

🔗

To test run:

TODO

Dependencies

🔗
  • rospy
  • sensor_msgs: for the Joy.msg
  • duckietown_msgs: for the CarControl.msg

Node adafruit_imu

🔗

This node reads sensor data from adafruit IMU and publishes it to sensor_msgs.Imu and sensor_msgs.MagneticField.

Parameters

🔗
  • ~pub_timestep: Time steps (in seconds) between publishings of CarControl msgs. Default to 0.02 (50 Hz).

Publish Topics

🔗
  • ~adafruit_imu: sensor_msgs.Imu

Imu.angular_velocity: Vector3 of angular velocity vector.

Imu.linear_acceleration: Vector3 of linear acceleration.

  • ~adafruit_mag: sensor_msgs.MagneticField

MagneticField.magnetic_field: Vector3 of magnetic field.

Services

🔗

None

Because of mathjax bug
Because of mathjax bug

Package car_supervisor

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add authors.

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

The car_supervisor package for duckietown.

Because of mathjax bug
Because of mathjax bug

Package scene_segmentation

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package scene_segmentation in package.xml.

Because of mathjax bug
Because of mathjax bug

Package visual_odometry_line

🔗

Package information

🔗

Link to package on Github

Essentials

🔗

add code to generate list of dependency.

add code to generate a link to a Github issue table for this package.

add code to show unit tests build indicator.

Descriptions

🔗

Add a description of package lane_filter in package.xml.